2 * Copyright 2006, The Android Open Source Project
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
13 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 #define LOG_TAG "webcoreglue"
29 #include "WebViewCore.h"
31 #include "AtomicString.h"
32 #include "BaseLayerAndroid.h"
33 #include "CachedNode.h"
34 #include "CachedRoot.h"
36 #include "ChromeClientAndroid.h"
38 #include "DatabaseTracker.h"
40 #include "DOMWindow.h"
41 #include "DOMSelection.h"
44 #include "EditorClientAndroid.h"
45 #include "EventHandler.h"
46 #include "EventNames.h"
47 #include "FocusController.h"
50 #include "FrameLoader.h"
51 #include "FrameLoaderClientAndroid.h"
52 #include "FrameTree.h"
53 #include "FrameView.h"
54 #include "Geolocation.h"
55 #include "GraphicsContext.h"
56 #include "GraphicsJNI.h"
57 #include "HTMLAnchorElement.h"
58 #include "HTMLAreaElement.h"
59 #include "HTMLElement.h"
60 #include "HTMLImageElement.h"
61 #include "HTMLInputElement.h"
62 #include "HTMLLabelElement.h"
63 #include "HTMLMapElement.h"
64 #include "HTMLNames.h"
65 #include "HTMLOptGroupElement.h"
66 #include "HTMLOptionElement.h"
67 #include "HTMLSelectElement.h"
68 #include "HTMLTextAreaElement.h"
69 #include "HistoryItem.h"
70 #include "HitTestRequest.h"
71 #include "HitTestResult.h"
72 #include "InlineTextBox.h"
73 #include "Navigator.h"
77 #include "PageGroup.h"
78 #include "PlatformKeyboardEvent.h"
79 #include "PlatformString.h"
80 #include "PluginWidgetAndroid.h"
81 #include "PluginView.h"
83 #include "ProgressTracker.h"
85 #include "RenderBox.h"
86 #include "RenderInline.h"
87 #include "RenderLayer.h"
88 #include "RenderPart.h"
89 #include "RenderText.h"
90 #include "RenderTextControl.h"
91 #include "RenderThemeAndroid.h"
92 #include "RenderView.h"
93 #include "ResourceRequest.h"
94 #include "SelectionController.h"
97 #include "SkTemplates.h"
98 #include "SkTDArray.h"
100 #include "SkCanvas.h"
101 #include "SkPicture.h"
103 #include "StringImpl.h"
105 #include "TypingCommand.h"
106 #include "WebCoreFrameBridge.h"
107 #include "WebFrameView.h"
108 #include "WindowsKeyboardCodes.h"
109 #include "android_graphics.h"
112 #include <JNIUtility.h>
113 #include <ui/KeycodeLabels.h>
114 #include <wtf/CurrentTime.h>
117 #include "ScriptController.h"
118 #include "V8Counters.h"
119 #include <wtf/text/CString.h>
126 #if ENABLE(TOUCH_EVENTS) // Android
127 #include "PlatformTouchEvent.h"
130 #ifdef ANDROID_DOM_LOGGING
131 #include "AndroidLog.h"
132 #include "RenderTreeAsText.h"
133 #include <wtf/text/CString.h>
135 FILE* gDomTreeFile = 0;
136 FILE* gRenderTreeFile = 0;
139 #ifdef ANDROID_INSTRUMENT
140 #include "TimeCounter.h"
143 #if USE(ACCELERATED_COMPOSITING)
144 #include "GraphicsLayerAndroid.h"
145 #include "RenderLayerCompositor.h"
148 /* We pass this flag when recording the actual content, so that we don't spend
149 time actually regionizing complex path clips, when all we really want to do
152 #define PICT_RECORD_FLAGS SkPicture::kUsePathBoundsForClip_RecordingFlag
154 ////////////////////////////////////////////////////////////////////////////////////////////////
158 static SkTDArray<WebViewCore*> gInstanceList;
160 void WebViewCore::addInstance(WebViewCore* inst) {
161 *gInstanceList.append() = inst;
164 void WebViewCore::removeInstance(WebViewCore* inst) {
165 int index = gInstanceList.find(inst);
166 LOG_ASSERT(index >= 0, "RemoveInstance inst not found");
168 gInstanceList.removeShuffle(index);
172 bool WebViewCore::isInstance(WebViewCore* inst) {
173 return gInstanceList.find(inst) >= 0;
176 jobject WebViewCore::getApplicationContext() {
178 // check to see if there is a valid webviewcore object
179 if (gInstanceList.isEmpty())
182 // get the context from the webview
183 jobject context = gInstanceList[0]->getContext();
188 // get the application context using JNI
189 JNIEnv* env = JSC::Bindings::getJNIEnv();
190 jclass contextClass = env->GetObjectClass(context);
191 jmethodID appContextMethod = env->GetMethodID(contextClass, "getApplicationContext", "()Landroid/content/Context;");
192 jobject result = env->CallObjectMethod(context, appContextMethod);
197 // ----------------------------------------------------------------------------
199 #define GET_NATIVE_VIEW(env, obj) ((WebViewCore*)env->GetIntField(obj, gWebViewCoreFields.m_nativeClass))
201 // Field ids for WebViewCore
202 struct WebViewCoreFields {
203 jfieldID m_nativeClass;
204 jfieldID m_viewportWidth;
205 jfieldID m_viewportHeight;
206 jfieldID m_viewportInitialScale;
207 jfieldID m_viewportMinimumScale;
208 jfieldID m_viewportMaximumScale;
209 jfieldID m_viewportUserScalable;
210 jfieldID m_viewportDensityDpi;
212 } gWebViewCoreFields;
214 // ----------------------------------------------------------------------------
216 struct WebViewCore::JavaGlue {
218 jmethodID m_spawnScrollTo;
219 jmethodID m_scrollTo;
220 jmethodID m_scrollBy;
221 jmethodID m_contentDraw;
222 jmethodID m_requestListBox;
223 jmethodID m_openFileChooser;
224 jmethodID m_requestSingleListBox;
226 jmethodID m_jsConfirm;
227 jmethodID m_jsPrompt;
228 jmethodID m_jsUnload;
229 jmethodID m_jsInterrupt;
230 jmethodID m_didFirstLayout;
231 jmethodID m_updateViewport;
232 jmethodID m_sendNotifyProgressFinished;
233 jmethodID m_sendViewInvalidate;
234 jmethodID m_updateTextfield;
235 jmethodID m_updateTextSelection;
236 jmethodID m_clearTextEntry;
237 jmethodID m_restoreScale;
238 jmethodID m_needTouchEvents;
239 jmethodID m_requestKeyboard;
240 jmethodID m_requestKeyboardWithSelection;
241 jmethodID m_exceededDatabaseQuota;
242 jmethodID m_reachedMaxAppCacheSize;
243 jmethodID m_populateVisitedLinks;
244 jmethodID m_geolocationPermissionsShowPrompt;
245 jmethodID m_geolocationPermissionsHidePrompt;
246 jmethodID m_addMessageToConsole;
247 jmethodID m_getPluginClass;
248 jmethodID m_showFullScreenPlugin;
249 jmethodID m_hideFullScreenPlugin;
250 jmethodID m_addSurface;
251 jmethodID m_updateSurface;
252 jmethodID m_destroySurface;
253 jmethodID m_getContext;
254 jmethodID m_sendFindAgain;
255 jmethodID m_showRect;
256 jmethodID m_centerFitRect;
257 jmethodID m_setScrollbarModes;
258 jmethodID m_setInstallableWebApp;
259 AutoJObject object(JNIEnv* env) {
260 return getRealObject(env, m_obj);
265 * WebViewCore Implementation
268 static jmethodID GetJMethod(JNIEnv* env, jclass clazz, const char name[], const char signature[])
270 jmethodID m = env->GetMethodID(clazz, name, signature);
271 LOG_ASSERT(m, "Could not find method %s", name);
275 Mutex WebViewCore::gFrameCacheMutex;
276 Mutex WebViewCore::gButtonMutex;
277 Mutex WebViewCore::gCursorBoundsMutex;
279 WebViewCore::WebViewCore(JNIEnv* env, jobject javaWebViewCore, WebCore::Frame* mainframe)
280 : m_pluginInvalTimer(this, &WebViewCore::pluginInvalTimerFired)
282 m_mainFrame = mainframe;
285 m_moveGeneration = 0;
286 m_lastGeneration = 0;
287 m_touchGeneration = 0;
288 m_blockTextfieldUpdates = false;
289 // just initial values. These should be set by client
290 m_maxXScroll = 320/4;
291 m_maxYScroll = 240/4;
292 m_textGeneration = 0;
294 m_textWrapWidth = 320;
296 #if ENABLE(TOUCH_EVENTS)
297 m_forwardingTouchEvents = false;
301 LOG_ASSERT(m_mainFrame, "Uh oh, somehow a frameview was made without an initial frame!");
303 jclass clazz = env->GetObjectClass(javaWebViewCore);
304 m_javaGlue = new JavaGlue;
305 m_javaGlue->m_obj = env->NewWeakGlobalRef(javaWebViewCore);
306 m_javaGlue->m_spawnScrollTo = GetJMethod(env, clazz, "contentSpawnScrollTo", "(II)V");
307 m_javaGlue->m_scrollTo = GetJMethod(env, clazz, "contentScrollTo", "(II)V");
308 m_javaGlue->m_scrollBy = GetJMethod(env, clazz, "contentScrollBy", "(IIZ)V");
309 m_javaGlue->m_contentDraw = GetJMethod(env, clazz, "contentDraw", "()V");
310 m_javaGlue->m_requestListBox = GetJMethod(env, clazz, "requestListBox", "([Ljava/lang/String;[I[I)V");
311 m_javaGlue->m_openFileChooser = GetJMethod(env, clazz, "openFileChooser", "(Ljava/lang/String;)Ljava/lang/String;");
312 m_javaGlue->m_requestSingleListBox = GetJMethod(env, clazz, "requestListBox", "([Ljava/lang/String;[II)V");
313 m_javaGlue->m_jsAlert = GetJMethod(env, clazz, "jsAlert", "(Ljava/lang/String;Ljava/lang/String;)V");
314 m_javaGlue->m_jsConfirm = GetJMethod(env, clazz, "jsConfirm", "(Ljava/lang/String;Ljava/lang/String;)Z");
315 m_javaGlue->m_jsPrompt = GetJMethod(env, clazz, "jsPrompt", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;");
316 m_javaGlue->m_jsUnload = GetJMethod(env, clazz, "jsUnload", "(Ljava/lang/String;Ljava/lang/String;)Z");
317 m_javaGlue->m_jsInterrupt = GetJMethod(env, clazz, "jsInterrupt", "()Z");
318 m_javaGlue->m_didFirstLayout = GetJMethod(env, clazz, "didFirstLayout", "(Z)V");
319 m_javaGlue->m_updateViewport = GetJMethod(env, clazz, "updateViewport", "()V");
320 m_javaGlue->m_sendNotifyProgressFinished = GetJMethod(env, clazz, "sendNotifyProgressFinished", "()V");
321 m_javaGlue->m_sendViewInvalidate = GetJMethod(env, clazz, "sendViewInvalidate", "(IIII)V");
322 m_javaGlue->m_updateTextfield = GetJMethod(env, clazz, "updateTextfield", "(IZLjava/lang/String;I)V");
323 m_javaGlue->m_updateTextSelection = GetJMethod(env, clazz, "updateTextSelection", "(IIII)V");
324 m_javaGlue->m_clearTextEntry = GetJMethod(env, clazz, "clearTextEntry", "()V");
325 m_javaGlue->m_restoreScale = GetJMethod(env, clazz, "restoreScale", "(II)V");
326 m_javaGlue->m_needTouchEvents = GetJMethod(env, clazz, "needTouchEvents", "(Z)V");
327 m_javaGlue->m_requestKeyboard = GetJMethod(env, clazz, "requestKeyboard", "(Z)V");
328 m_javaGlue->m_requestKeyboardWithSelection = GetJMethod(env, clazz, "requestKeyboardWithSelection", "(IIII)V");
329 m_javaGlue->m_exceededDatabaseQuota = GetJMethod(env, clazz, "exceededDatabaseQuota", "(Ljava/lang/String;Ljava/lang/String;JJ)V");
330 m_javaGlue->m_reachedMaxAppCacheSize = GetJMethod(env, clazz, "reachedMaxAppCacheSize", "(J)V");
331 m_javaGlue->m_populateVisitedLinks = GetJMethod(env, clazz, "populateVisitedLinks", "()V");
332 m_javaGlue->m_geolocationPermissionsShowPrompt = GetJMethod(env, clazz, "geolocationPermissionsShowPrompt", "(Ljava/lang/String;)V");
333 m_javaGlue->m_geolocationPermissionsHidePrompt = GetJMethod(env, clazz, "geolocationPermissionsHidePrompt", "()V");
334 m_javaGlue->m_addMessageToConsole = GetJMethod(env, clazz, "addMessageToConsole", "(Ljava/lang/String;ILjava/lang/String;I)V");
335 m_javaGlue->m_getPluginClass = GetJMethod(env, clazz, "getPluginClass", "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/Class;");
336 m_javaGlue->m_showFullScreenPlugin = GetJMethod(env, clazz, "showFullScreenPlugin", "(Landroid/webkit/ViewManager$ChildView;I)V");
337 m_javaGlue->m_hideFullScreenPlugin = GetJMethod(env, clazz, "hideFullScreenPlugin", "()V");
338 m_javaGlue->m_addSurface = GetJMethod(env, clazz, "addSurface", "(Landroid/view/View;IIII)Landroid/webkit/ViewManager$ChildView;");
339 m_javaGlue->m_updateSurface = GetJMethod(env, clazz, "updateSurface", "(Landroid/webkit/ViewManager$ChildView;IIII)V");
340 m_javaGlue->m_destroySurface = GetJMethod(env, clazz, "destroySurface", "(Landroid/webkit/ViewManager$ChildView;)V");
341 m_javaGlue->m_getContext = GetJMethod(env, clazz, "getContext", "()Landroid/content/Context;");
342 m_javaGlue->m_sendFindAgain = GetJMethod(env, clazz, "sendFindAgain", "()V");
343 m_javaGlue->m_showRect = GetJMethod(env, clazz, "showRect", "(IIIIIIFFFF)V");
344 m_javaGlue->m_centerFitRect = GetJMethod(env, clazz, "centerFitRect", "(IIII)V");
345 m_javaGlue->m_setScrollbarModes = GetJMethod(env, clazz, "setScrollbarModes", "(II)V");
346 m_javaGlue->m_setInstallableWebApp = GetJMethod(env, clazz, "setInstallableWebApp", "()V");
348 env->SetIntField(javaWebViewCore, gWebViewCoreFields.m_nativeClass, (jint)this);
350 m_scrollOffsetX = m_scrollOffsetY = 0;
352 PageGroup::setShouldTrackVisitedLinks(true);
356 WebViewCore::addInstance(this);
359 WebViewCore::~WebViewCore()
361 WebViewCore::removeInstance(this);
363 // Release the focused view
364 Release(m_popupReply);
366 if (m_javaGlue->m_obj) {
367 JNIEnv* env = JSC::Bindings::getJNIEnv();
368 env->DeleteWeakGlobalRef(m_javaGlue->m_obj);
369 m_javaGlue->m_obj = 0;
372 delete m_frameCacheKit;
373 delete m_navPictureKit;
376 WebViewCore* WebViewCore::getWebViewCore(const WebCore::FrameView* view)
378 return getWebViewCore(static_cast<const WebCore::ScrollView*>(view));
381 WebViewCore* WebViewCore::getWebViewCore(const WebCore::ScrollView* view)
386 WebFrameView* webFrameView = static_cast<WebFrameView*>(view->platformWidget());
389 return webFrameView->webViewCore();
392 void WebViewCore::reset(bool fromConstructor)
395 if (fromConstructor) {
399 gFrameCacheMutex.lock();
400 delete m_frameCacheKit;
401 delete m_navPictureKit;
404 gFrameCacheMutex.unlock();
408 m_lastFocusedBounds = WebCore::IntRect(0,0,0,0);
409 m_focusBoundsChanged = false;
410 m_lastFocusedSelStart = 0;
411 m_lastFocusedSelEnd = 0;
413 m_updatedFrameCache = true;
414 m_frameCacheOutOfDate = true;
415 m_skipContentDraw = false;
417 m_domtree_version = 0;
418 m_check_domtree_version = true;
419 m_progressDone = false;
420 m_hasCursorBounds = false;
426 m_groupForVisitedLinks = NULL;
429 static bool layoutIfNeededRecursive(WebCore::Frame* f)
434 WebCore::FrameView* v = f->view();
438 if (v->needsLayout())
439 v->layout(f->tree()->parent());
441 WebCore::Frame* child = f->tree()->firstChild();
444 success &= layoutIfNeededRecursive(child);
445 child = child->tree()->nextSibling();
448 return success && !v->needsLayout();
451 CacheBuilder& WebViewCore::cacheBuilder()
453 return FrameLoaderClientAndroid::get(m_mainFrame)->getCacheBuilder();
456 WebCore::Node* WebViewCore::currentFocus()
458 return cacheBuilder().currentFocus();
461 void WebViewCore::recordPicture(SkPicture* picture)
463 // if there is no document yet, just return
464 if (!m_mainFrame->document()) {
465 DBG_NAV_LOG("no document");
468 // Call layout to ensure that the contentWidth and contentHeight are correct
469 if (!layoutIfNeededRecursive(m_mainFrame)) {
470 DBG_NAV_LOG("layout failed");
473 // draw into the picture's recording canvas
474 WebCore::FrameView* view = m_mainFrame->view();
475 DBG_NAV_LOGD("view=(w=%d,h=%d)", view->contentsWidth(),
476 view->contentsHeight());
477 SkAutoPictureRecord arp(picture, view->contentsWidth(),
478 view->contentsHeight(), PICT_RECORD_FLAGS);
479 SkAutoMemoryUsageProbe mup(__FUNCTION__);
481 // Copy m_buttons so we can pass it to our graphics context.
483 WTF::Vector<Container> buttons(m_buttons);
484 gButtonMutex.unlock();
486 WebCore::PlatformGraphicsContext pgc(arp.getRecordingCanvas(), &buttons);
487 WebCore::GraphicsContext gc(&pgc);
488 view->platformWidget()->draw(&gc, WebCore::IntRect(0, 0,
489 view->contentsWidth(), view->contentsHeight()));
492 updateButtonList(&buttons);
493 gButtonMutex.unlock();
496 void WebViewCore::recordPictureSet(PictureSet* content)
498 // if there is no document yet, just return
499 if (!m_mainFrame->document()) {
500 DBG_SET_LOG("!m_mainFrame->document()");
503 if (m_addInval.isEmpty()) {
504 DBG_SET_LOG("m_addInval.isEmpty()");
507 // Call layout to ensure that the contentWidth and contentHeight are correct
508 // it's fine for layout to gather invalidates, but defeat sending a message
509 // back to java to call webkitDraw, since we're already in the middle of
511 m_skipContentDraw = true;
512 bool success = layoutIfNeededRecursive(m_mainFrame);
513 m_skipContentDraw = false;
515 // We may be mid-layout and thus cannot draw.
519 { // collect WebViewCoreRecordTimeCounter after layoutIfNeededRecursive
520 #ifdef ANDROID_INSTRUMENT
521 TimeCounterAuto counter(TimeCounter::WebViewCoreRecordTimeCounter);
524 // if the webkit page dimensions changed, discard the pictureset and redraw.
525 WebCore::FrameView* view = m_mainFrame->view();
526 int width = view->contentsWidth();
527 int height = view->contentsHeight();
529 // Use the contents width and height as a starting point.
531 contentRect.set(0, 0, width, height);
532 SkIRect total(contentRect);
534 // Traverse all the frames and add their sizes if they are in the visible
536 for (WebCore::Frame* frame = m_mainFrame->tree()->traverseNext(); frame;
537 frame = frame->tree()->traverseNext()) {
538 // If the frame doesn't have an owner then it is the top frame and the
539 // view size is the frame size.
540 WebCore::RenderPart* owner = frame->ownerRenderer();
541 if (owner && owner->style()->visibility() == VISIBLE) {
545 // Traverse the tree up to the parent to find the absolute position
547 WebCore::Frame* parent = frame->tree()->parent();
549 WebCore::RenderPart* parentOwner = parent->ownerRenderer();
551 x += parentOwner->x();
552 y += parentOwner->y();
554 parent = parent->tree()->parent();
556 // Use the owner dimensions so that padding and border are
558 int right = x + owner->width();
559 int bottom = y + owner->height();
560 SkIRect frameRect = {x, y, right, bottom};
561 // Ignore a width or height that is smaller than 1. Some iframes
562 // have small dimensions in order to be hidden. The iframe
563 // expansion code does not expand in that case so we should ignore
565 if (frameRect.width() > 1 && frameRect.height() > 1
566 && SkIRect::Intersects(total, frameRect))
567 total.join(x, y, right, bottom);
571 // If the new total is larger than the content, resize the view to include
573 if (!contentRect.contains(total)) {
574 // Resize the view to change the overflow clip.
575 view->resize(total.fRight, total.fBottom);
577 // We have to force a layout in order for the clip to change.
578 m_mainFrame->contentRenderer()->setNeedsLayoutAndPrefWidthsRecalc();
581 // Relayout similar to above
582 m_skipContentDraw = true;
583 bool success = layoutIfNeededRecursive(m_mainFrame);
584 m_skipContentDraw = false;
588 // Set the computed content width
589 width = view->contentsWidth();
590 height = view->contentsHeight();
593 if (cacheBuilder().pictureSetDisabled())
596 content->checkDimensions(width, height, &m_addInval);
598 // The inval region may replace existing pictures. The existing pictures
599 // may have already been split into pieces. If reuseSubdivided() returns
600 // true, the split pieces are the last entries in the picture already. They
601 // are marked as invalid, and are rebuilt by rebuildPictureSet().
603 // If the new region doesn't match a set of split pieces, add it to the end.
604 if (!content->reuseSubdivided(m_addInval)) {
605 const SkIRect& inval = m_addInval.getBounds();
606 SkPicture* picture = rebuildPicture(inval);
607 DBG_SET_LOGD("{%d,%d,w=%d,h=%d}", inval.fLeft,
608 inval.fTop, inval.width(), inval.height());
609 content->add(m_addInval, picture, 0, false);
610 picture->safeUnref();
612 // Remove any pictures already in the set that are obscured by the new one,
613 // and check to see if any already split pieces need to be redrawn.
614 if (content->build())
615 rebuildPictureSet(content);
616 } // WebViewCoreRecordTimeCounter
617 WebCore::Node* oldFocusNode = currentFocus();
618 m_frameCacheOutOfDate = true;
619 WebCore::IntRect oldBounds;
623 oldBounds = oldFocusNode->getRect();
624 RenderObject* renderer = oldFocusNode->renderer();
625 if (renderer && (renderer->isTextArea() || renderer->isTextField())) {
626 WebCore::RenderTextControl* rtc =
627 static_cast<WebCore::RenderTextControl*>(renderer);
628 oldSelStart = rtc->selectionStart();
629 oldSelEnd = rtc->selectionEnd();
632 oldBounds = WebCore::IntRect(0,0,0,0);
633 unsigned latestVersion = 0;
634 if (m_check_domtree_version) {
635 // as domTreeVersion only increment, we can just check the sum to see
636 // whether we need to update the frame cache
637 for (Frame* frame = m_mainFrame; frame; frame = frame->tree()->traverseNext()) {
638 latestVersion += frame->document()->domTreeVersion();
641 DBG_NAV_LOGD("m_lastFocused=%p oldFocusNode=%p"
642 " m_lastFocusedBounds={%d,%d,%d,%d} oldBounds={%d,%d,%d,%d}"
643 " m_lastFocusedSelection={%d,%d} oldSelection={%d,%d}"
644 " m_check_domtree_version=%s latestVersion=%d m_domtree_version=%d",
645 m_lastFocused, oldFocusNode,
646 m_lastFocusedBounds.x(), m_lastFocusedBounds.y(),
647 m_lastFocusedBounds.width(), m_lastFocusedBounds.height(),
648 oldBounds.x(), oldBounds.y(), oldBounds.width(), oldBounds.height(),
649 m_lastFocusedSelStart, m_lastFocusedSelEnd, oldSelStart, oldSelEnd,
650 m_check_domtree_version ? "true" : "false",
651 latestVersion, m_domtree_version);
652 if (m_lastFocused == oldFocusNode && m_lastFocusedBounds == oldBounds
653 && m_lastFocusedSelStart == oldSelStart
654 && m_lastFocusedSelEnd == oldSelEnd
656 && (!m_check_domtree_version || latestVersion == m_domtree_version))
660 m_focusBoundsChanged |= m_lastFocused == oldFocusNode
661 && m_lastFocusedBounds != oldBounds;
662 m_lastFocused = oldFocusNode;
663 m_lastFocusedBounds = oldBounds;
664 m_lastFocusedSelStart = oldSelStart;
665 m_lastFocusedSelEnd = oldSelEnd;
666 m_domtree_version = latestVersion;
667 DBG_NAV_LOG("call updateFrameCache");
670 LOG_ASSERT(m_javaGlue->m_obj,
671 "A Java widget was not associated with this view bridge!");
672 JNIEnv* env = JSC::Bindings::getJNIEnv();
673 env->CallVoidMethod(m_javaGlue->object(env).get(),
674 m_javaGlue->m_sendFindAgain);
679 void WebViewCore::updateButtonList(WTF::Vector<Container>* buttons)
681 // All the entries in buttons are either updates of previous entries in
682 // m_buttons or they need to be added to it.
683 Container* end = buttons->end();
684 for (Container* updatedContainer = buttons->begin();
685 updatedContainer != end; updatedContainer++) {
686 bool updated = false;
687 // Search for a previous entry that references the same node as our new
689 Container* lastPossibleMatch = m_buttons.end();
690 for (Container* possibleMatch = m_buttons.begin();
691 possibleMatch != lastPossibleMatch; possibleMatch++) {
692 if (updatedContainer->matches(possibleMatch->node())) {
693 // Update our record, and skip to the next one.
694 possibleMatch->setRect(updatedContainer->rect());
700 // This is a brand new button, so append it to m_buttons
701 m_buttons.append(*updatedContainer);
705 // count will decrease each time one is removed, so check count each time.
706 while (i < m_buttons.size()) {
707 if (m_buttons[i].canBeRemoved()) {
708 m_buttons[i] = m_buttons.last();
709 m_buttons.removeLast();
716 // note: updateCursorBounds is called directly by the WebView thread
717 // This needs to be called each time we call CachedRoot::setCursor() with
718 // non-null CachedNode/CachedFrame, since otherwise the WebViewCore's data
719 // about the cursor is incorrect. When we call setCursor(0,0), we need
720 // to set hasCursorBounds to false.
721 void WebViewCore::updateCursorBounds(const CachedRoot* root,
722 const CachedFrame* cachedFrame, const CachedNode* cachedNode)
724 LOG_ASSERT(root, "updateCursorBounds: root cannot be null");
725 LOG_ASSERT(cachedNode, "updateCursorBounds: cachedNode cannot be null");
726 LOG_ASSERT(cachedFrame, "updateCursorBounds: cachedFrame cannot be null");
727 gCursorBoundsMutex.lock();
728 m_hasCursorBounds = !cachedNode->isHidden();
729 // If m_hasCursorBounds is false, we never look at the other
730 // values, so do not bother setting them.
731 if (m_hasCursorBounds) {
732 WebCore::IntRect bounds = cachedNode->bounds(cachedFrame);
733 if (m_cursorBounds != bounds)
734 DBG_NAV_LOGD("new cursor bounds=(%d,%d,w=%d,h=%d)",
735 bounds.x(), bounds.y(), bounds.width(), bounds.height());
736 m_cursorBounds = bounds;
737 m_cursorHitBounds = cachedNode->hitBounds(cachedFrame);
738 m_cursorFrame = cachedFrame->framePointer();
739 root->getSimulatedMousePosition(&m_cursorLocation);
740 m_cursorNode = cachedNode->nodePointer();
742 gCursorBoundsMutex.unlock();
745 void WebViewCore::clearContent()
749 m_addInval.setEmpty();
750 m_rebuildInval.setEmpty();
753 bool WebViewCore::focusBoundsChanged()
755 bool result = m_focusBoundsChanged;
756 m_focusBoundsChanged = false;
760 SkPicture* WebViewCore::rebuildPicture(const SkIRect& inval)
762 WebCore::FrameView* view = m_mainFrame->view();
763 int width = view->contentsWidth();
764 int height = view->contentsHeight();
765 SkPicture* picture = new SkPicture();
766 SkAutoPictureRecord arp(picture, width, height, PICT_RECORD_FLAGS);
767 SkAutoMemoryUsageProbe mup(__FUNCTION__);
768 SkCanvas* recordingCanvas = arp.getRecordingCanvas();
771 WTF::Vector<Container> buttons(m_buttons);
772 gButtonMutex.unlock();
774 WebCore::PlatformGraphicsContext pgc(recordingCanvas, &buttons);
775 WebCore::GraphicsContext gc(&pgc);
776 recordingCanvas->translate(-inval.fLeft, -inval.fTop);
777 recordingCanvas->save();
778 view->platformWidget()->draw(&gc, WebCore::IntRect(inval.fLeft,
779 inval.fTop, inval.width(), inval.height()));
780 m_rebuildInval.op(inval, SkRegion::kUnion_Op);
781 DBG_SET_LOGD("m_rebuildInval={%d,%d,r=%d,b=%d}",
782 m_rebuildInval.getBounds().fLeft, m_rebuildInval.getBounds().fTop,
783 m_rebuildInval.getBounds().fRight, m_rebuildInval.getBounds().fBottom);
786 updateButtonList(&buttons);
787 gButtonMutex.unlock();
792 void WebViewCore::rebuildPictureSet(PictureSet* pictureSet)
794 WebCore::FrameView* view = m_mainFrame->view();
795 size_t size = pictureSet->size();
796 for (size_t index = 0; index < size; index++) {
797 if (pictureSet->upToDate(index))
799 const SkIRect& inval = pictureSet->bounds(index);
800 DBG_SET_LOGD("pictSet=%p [%d] {%d,%d,w=%d,h=%d}", pictureSet, index,
801 inval.fLeft, inval.fTop, inval.width(), inval.height());
802 pictureSet->setPicture(index, rebuildPicture(inval));
804 pictureSet->validate(__FUNCTION__);
807 BaseLayerAndroid* WebViewCore::recordContent(SkRegion* region, SkIPoint* point)
809 DBG_SET_LOG("start");
810 float progress = (float) m_mainFrame->page()->progress()->estimatedProgress();
811 m_progressDone = progress <= 0.0f || progress >= 1.0f;
812 recordPictureSet(&m_content);
813 if (!m_progressDone && m_content.isEmpty()) {
814 DBG_SET_LOGD("empty (progress=%g)", progress);
817 region->set(m_addInval);
818 m_addInval.setEmpty();
819 region->op(m_rebuildInval, SkRegion::kUnion_Op);
820 m_rebuildInval.setEmpty();
821 point->fX = m_content.width();
822 point->fY = m_content.height();
823 DBG_SET_LOGD("region={%d,%d,r=%d,b=%d}", region->getBounds().fLeft,
824 region->getBounds().fTop, region->getBounds().fRight,
825 region->getBounds().fBottom);
828 BaseLayerAndroid* base = new BaseLayerAndroid();
829 base->setContent(m_content);
831 #if USE(ACCELERATED_COMPOSITING)
832 // We update the layers
833 ChromeClientAndroid* chromeC = static_cast<ChromeClientAndroid*>(m_mainFrame->page()->chrome()->client());
834 GraphicsLayerAndroid* root = static_cast<GraphicsLayerAndroid*>(chromeC->layersSync());
836 root->notifyClientAnimationStarted();
837 LayerAndroid* copyLayer = new LayerAndroid(*root->contentLayer());
838 base->addChild(copyLayer);
846 void WebViewCore::splitContent(PictureSet* content)
848 bool layoutSuceeded = layoutIfNeededRecursive(m_mainFrame);
849 LOG_ASSERT(layoutSuceeded, "Can never be called recursively");
850 content->split(&m_content);
851 rebuildPictureSet(&m_content);
852 content->set(m_content);
855 void WebViewCore::scrollTo(int x, int y, bool animate)
857 LOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!");
859 // LOGD("WebViewCore::scrollTo(%d %d)\n", x, y);
861 JNIEnv* env = JSC::Bindings::getJNIEnv();
862 env->CallVoidMethod(m_javaGlue->object(env).get(),
863 animate ? m_javaGlue->m_spawnScrollTo : m_javaGlue->m_scrollTo,
868 void WebViewCore::sendNotifyProgressFinished()
870 LOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!");
871 JNIEnv* env = JSC::Bindings::getJNIEnv();
872 env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_sendNotifyProgressFinished);
876 void WebViewCore::viewInvalidate(const WebCore::IntRect& rect)
878 LOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!");
879 JNIEnv* env = JSC::Bindings::getJNIEnv();
880 env->CallVoidMethod(m_javaGlue->object(env).get(),
881 m_javaGlue->m_sendViewInvalidate,
882 rect.x(), rect.y(), rect.right(), rect.bottom());
886 void WebViewCore::scrollBy(int dx, int dy, bool animate)
890 JNIEnv* env = JSC::Bindings::getJNIEnv();
891 env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_scrollBy,
896 void WebViewCore::contentDraw()
898 JNIEnv* env = JSC::Bindings::getJNIEnv();
899 env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_contentDraw);
903 void WebViewCore::contentInvalidate(const WebCore::IntRect &r)
905 DBG_SET_LOGD("rect={%d,%d,w=%d,h=%d}", r.x(), r.y(), r.width(), r.height());
907 if (!rect.intersect(0, 0, INT_MAX, INT_MAX))
909 m_addInval.op(rect, SkRegion::kUnion_Op);
910 DBG_SET_LOGD("m_addInval={%d,%d,r=%d,b=%d}",
911 m_addInval.getBounds().fLeft, m_addInval.getBounds().fTop,
912 m_addInval.getBounds().fRight, m_addInval.getBounds().fBottom);
913 if (!m_skipContentDraw)
917 void WebViewCore::offInvalidate(const WebCore::IntRect &r)
919 // FIXME: these invalidates are offscreen, and can be throttled or
920 // deferred until the area is visible. For now, treat them as
921 // regular invals so that drawing happens (inefficiently) for now.
922 contentInvalidate(r);
925 static int pin_pos(int x, int width, int targetWidth)
927 if (x + width > targetWidth)
928 x = targetWidth - width;
934 void WebViewCore::didFirstLayout()
936 DEBUG_NAV_UI_LOGD("%s", __FUNCTION__);
937 LOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!");
939 WebCore::FrameLoader* loader = m_mainFrame->loader();
940 const WebCore::KURL& url = loader->url();
943 LOGV("::WebCore:: didFirstLayout %s", url.string().ascii().data());
945 WebCore::FrameLoadType loadType = loader->loadType();
947 JNIEnv* env = JSC::Bindings::getJNIEnv();
948 env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_didFirstLayout,
949 loadType == WebCore::FrameLoadTypeStandard
950 // When redirect with locked history, we would like to reset the
951 // scale factor. This is important for www.yahoo.com as it is
952 // redirected to www.yahoo.com/?rs=1 on load.
953 || loadType == WebCore::FrameLoadTypeRedirectWithLockedBackForwardList);
956 DBG_NAV_LOG("call updateFrameCache");
957 m_check_domtree_version = false;
959 m_history.setDidFirstLayout(true);
962 void WebViewCore::updateViewport()
964 DEBUG_NAV_UI_LOGD("%s", __FUNCTION__);
965 LOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!");
967 JNIEnv* env = JSC::Bindings::getJNIEnv();
968 env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_updateViewport);
972 void WebViewCore::restoreScale(int scale, int textWrapScale)
974 DEBUG_NAV_UI_LOGD("%s", __FUNCTION__);
975 LOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!");
977 JNIEnv* env = JSC::Bindings::getJNIEnv();
978 env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_restoreScale, scale, textWrapScale);
982 void WebViewCore::needTouchEvents(bool need)
984 DEBUG_NAV_UI_LOGD("%s", __FUNCTION__);
985 LOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!");
987 #if ENABLE(TOUCH_EVENTS)
988 if (m_forwardingTouchEvents == need)
991 JNIEnv* env = JSC::Bindings::getJNIEnv();
992 env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_needTouchEvents, need);
995 m_forwardingTouchEvents = need;
999 void WebViewCore::requestKeyboardWithSelection(const WebCore::Node* node,
1000 int selStart, int selEnd)
1002 DEBUG_NAV_UI_LOGD("%s", __FUNCTION__);
1003 LOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!");
1005 JNIEnv* env = JSC::Bindings::getJNIEnv();
1006 env->CallVoidMethod(m_javaGlue->object(env).get(),
1007 m_javaGlue->m_requestKeyboardWithSelection,
1008 reinterpret_cast<int>(node), selStart, selEnd, m_textGeneration);
1009 checkException(env);
1012 void WebViewCore::requestKeyboard(bool showKeyboard)
1014 DEBUG_NAV_UI_LOGD("%s", __FUNCTION__);
1015 LOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!");
1017 JNIEnv* env = JSC::Bindings::getJNIEnv();
1018 env->CallVoidMethod(m_javaGlue->object(env).get(),
1019 m_javaGlue->m_requestKeyboard, showKeyboard);
1020 checkException(env);
1023 void WebViewCore::notifyProgressFinished()
1025 DBG_NAV_LOG("call updateFrameCache");
1026 m_check_domtree_version = true;
1028 sendNotifyProgressFinished();
1031 void WebViewCore::doMaxScroll(CacheBuilder::Direction dir)
1036 case CacheBuilder::LEFT:
1039 case CacheBuilder::UP:
1042 case CacheBuilder::RIGHT:
1045 case CacheBuilder::DOWN:
1048 case CacheBuilder::UNINITIALIZED:
1050 LOG_ASSERT(0, "unexpected focus selector");
1052 this->scrollBy(dx, dy, true);
1055 void WebViewCore::setScrollOffset(int moveGeneration, int dx, int dy)
1057 DBG_NAV_LOGD("{%d,%d} m_scrollOffset=(%d,%d)", dx, dy,
1058 m_scrollOffsetX, m_scrollOffsetY);
1059 if (m_scrollOffsetX != dx || m_scrollOffsetY != dy) {
1060 m_scrollOffsetX = dx;
1061 m_scrollOffsetY = dy;
1062 // The visible rect is located within our coordinate space so it
1063 // contains the actual scroll position. Setting the location makes hit
1064 // testing work correctly.
1065 m_mainFrame->view()->platformWidget()->setLocation(m_scrollOffsetX,
1067 m_mainFrame->eventHandler()->sendScrollEvent();
1069 // update the currently visible screen
1070 sendPluginVisibleScreen();
1072 gCursorBoundsMutex.lock();
1073 bool hasCursorBounds = m_hasCursorBounds;
1074 Frame* frame = (Frame*) m_cursorFrame;
1075 IntPoint location = m_cursorLocation;
1076 gCursorBoundsMutex.unlock();
1077 if (!hasCursorBounds)
1079 moveMouseIfLatest(moveGeneration, frame, location.x(), location.y());
1082 void WebViewCore::setGlobalBounds(int x, int y, int h, int v)
1084 DBG_NAV_LOGD("{%d,%d}", x, y);
1085 m_mainFrame->view()->platformWidget()->setWindowBounds(x, y, h, v);
1088 void WebViewCore::setSizeScreenWidthAndScale(int width, int height,
1089 int textWrapWidth, float scale, int screenWidth, int screenHeight,
1090 int anchorX, int anchorY, bool ignoreHeight)
1092 WebCoreViewBridge* window = m_mainFrame->view()->platformWidget();
1093 int ow = window->width();
1094 int oh = window->height();
1095 window->setSize(width, height);
1096 window->setVisibleSize(screenWidth, screenHeight);
1097 if (width != screenWidth) {
1098 m_mainFrame->view()->setUseFixedLayout(true);
1099 m_mainFrame->view()->setFixedLayoutSize(IntSize(width, height));
1101 m_mainFrame->view()->setUseFixedLayout(false);
1103 int osw = m_screenWidth;
1104 int osh = m_screenHeight;
1105 int otw = m_textWrapWidth;
1106 DBG_NAV_LOGD("old:(w=%d,h=%d,sw=%d,scale=%g) new:(w=%d,h=%d,sw=%d,scale=%g)",
1107 ow, oh, osw, m_scale, width, height, screenWidth, scale);
1108 m_screenWidth = screenWidth;
1109 m_screenHeight = screenHeight;
1110 m_textWrapWidth = textWrapWidth;
1111 if (scale >= 0) // negative means keep the current scale
1113 m_maxXScroll = screenWidth >> 2;
1114 m_maxYScroll = m_maxXScroll * height / width;
1115 if (ow != width || (!ignoreHeight && oh != height) || otw != textWrapWidth) {
1116 WebCore::RenderObject *r = m_mainFrame->contentRenderer();
1117 DBG_NAV_LOGD("renderer=%p view=(w=%d,h=%d)", r,
1118 screenWidth, screenHeight);
1120 WebCore::IntPoint anchorPoint = WebCore::IntPoint(anchorX, anchorY);
1121 DBG_NAV_LOGD("anchorX=%d anchorY=%d", anchorX, anchorY);
1122 RefPtr<WebCore::Node> node;
1123 WebCore::IntRect bounds;
1124 WebCore::IntPoint offset;
1125 // If the text wrap changed, it is probably zoom change or
1126 // orientation change. Try to keep the anchor at the same place.
1127 if (otw && textWrapWidth && otw != textWrapWidth) {
1128 WebCore::HitTestResult hitTestResult =
1129 m_mainFrame->eventHandler()-> hitTestResultAtPoint(
1130 anchorPoint, false);
1131 node = hitTestResult.innerNode();
1134 bounds = node->getRect();
1135 DBG_NAV_LOGD("ob:(x=%d,y=%d,w=%d,h=%d)",
1136 bounds.x(), bounds.y(), bounds.width(), bounds.height());
1137 // sites like nytimes.com insert a non-standard tag <nyt_text>
1138 // in the html. If it is the HitTestResult, it may have zero
1139 // width and height. In this case, use its parent node.
1140 if (bounds.width() == 0) {
1141 node = node->parent();
1143 bounds = node->getRect();
1144 DBG_NAV_LOGD("found a zero width node and use its parent, whose ob:(x=%d,y=%d,w=%d,h=%d)",
1145 bounds.x(), bounds.y(), bounds.width(), bounds.height());
1149 r->setNeedsLayoutAndPrefWidthsRecalc();
1150 m_mainFrame->view()->forceLayout();
1151 // scroll to restore current screen center
1153 const WebCore::IntRect& newBounds = node->getRect();
1154 DBG_NAV_LOGD("nb:(x=%d,y=%d,w=%d,"
1155 "h=%d)", newBounds.x(), newBounds.y(),
1156 newBounds.width(), newBounds.height());
1157 if ((osw && osh && bounds.width() && bounds.height())
1158 && (bounds != newBounds)) {
1159 WebCore::FrameView* view = m_mainFrame->view();
1160 // force left align if width is not changed while height changed.
1161 // the anchorPoint is probably at some white space in the node
1162 // which is affected by text wrap around the screen width.
1163 const bool leftAlign = (otw != textWrapWidth)
1164 && (bounds.width() == newBounds.width())
1165 && (bounds.height() != newBounds.height());
1166 const float xPercentInDoc =
1167 leftAlign ? 0.0 : (float) (anchorX - bounds.x()) / bounds.width();
1168 const float xPercentInView =
1169 leftAlign ? 0.0 : (float) (anchorX - m_scrollOffsetX) / osw;
1170 const float yPercentInDoc = (float) (anchorY - bounds.y()) / bounds.height();
1171 const float yPercentInView = (float) (anchorY - m_scrollOffsetY) / osh;
1172 showRect(newBounds.x(), newBounds.y(), newBounds.width(),
1173 newBounds.height(), view->contentsWidth(),
1174 view->contentsHeight(),
1175 xPercentInDoc, xPercentInView,
1176 yPercentInDoc, yPercentInView);
1182 // update the currently visible screen as perceived by the plugin
1183 sendPluginVisibleScreen();
1186 void WebViewCore::dumpDomTree(bool useFile)
1188 #ifdef ANDROID_DOM_LOGGING
1190 gDomTreeFile = fopen(DOM_TREE_LOG_FILE, "w");
1191 m_mainFrame->document()->showTreeForThis();
1193 fclose(gDomTreeFile);
1199 void WebViewCore::dumpRenderTree(bool useFile)
1201 #ifdef ANDROID_DOM_LOGGING
1202 WTF::CString renderDump = WebCore::externalRepresentation(m_mainFrame).utf8();
1203 const char* data = renderDump.data();
1205 gRenderTreeFile = fopen(RENDER_TREE_LOG_FILE, "w");
1206 DUMP_RENDER_LOGD("%s", data);
1207 fclose(gRenderTreeFile);
1208 gRenderTreeFile = 0;
1210 // adb log can only output 1024 characters, so write out line by line.
1211 // exclude '\n' as adb log adds it for each output.
1212 int length = renderDump.length();
1213 for (int i = 0, last = 0; i < length; i++) {
1214 if (data[i] == '\n') {
1216 DUMP_RENDER_LOGD("%.*s", (i - last), &(data[last]));
1224 void WebViewCore::dumpNavTree()
1227 cacheBuilder().mDebug.print();
1231 WebCore::HTMLAnchorElement* WebViewCore::retrieveAnchorElement(WebCore::Frame* frame, WebCore::Node* node)
1233 if (!CacheBuilder::validNode(m_mainFrame, frame, node))
1235 if (!node->hasTagName(WebCore::HTMLNames::aTag))
1237 return static_cast<WebCore::HTMLAnchorElement*>(node);
1240 WebCore::String WebViewCore::retrieveHref(WebCore::Frame* frame, WebCore::Node* node)
1242 WebCore::HTMLAnchorElement* anchor = retrieveAnchorElement(frame, node);
1243 return anchor ? anchor->href() : WebCore::String();
1246 WebCore::String WebViewCore::retrieveAnchorText(WebCore::Frame* frame, WebCore::Node* node)
1248 WebCore::HTMLAnchorElement* anchor = retrieveAnchorElement(frame, node);
1249 return anchor ? anchor->text() : WebCore::String();
1252 WebCore::String WebViewCore::requestLabel(WebCore::Frame* frame,
1253 WebCore::Node* node)
1255 if (node && CacheBuilder::validNode(m_mainFrame, frame, node)) {
1256 RefPtr<WebCore::NodeList> list = node->document()->getElementsByTagName("label");
1257 unsigned length = list->length();
1258 for (unsigned i = 0; i < length; i++) {
1259 WebCore::HTMLLabelElement* label = static_cast<WebCore::HTMLLabelElement*>(
1261 if (label->control() == node) {
1264 while ((node = node->traverseNextNode(label))) {
1265 if (node->isTextNode()) {
1266 Text* textNode = static_cast<Text*>(node);
1267 result += textNode->dataImpl();
1274 return WebCore::String();
1277 void WebViewCore::updateCacheOnNodeChange()
1279 gCursorBoundsMutex.lock();
1280 bool hasCursorBounds = m_hasCursorBounds;
1281 Frame* frame = (Frame*) m_cursorFrame;
1282 Node* node = (Node*) m_cursorNode;
1283 IntRect bounds = m_cursorHitBounds;
1284 gCursorBoundsMutex.unlock();
1285 if (!hasCursorBounds || !node)
1287 if (CacheBuilder::validNode(m_mainFrame, frame, node)) {
1288 RenderObject* renderer = node->renderer();
1289 if (renderer && renderer->style()->visibility() != HIDDEN) {
1290 IntRect absBox = renderer->absoluteBoundingBoxRect();
1291 int globalX, globalY;
1292 CacheBuilder::GetGlobalOffset(frame, &globalX, &globalY);
1293 absBox.move(globalX, globalY);
1294 if (absBox == bounds)
1296 DBG_NAV_LOGD("absBox=(%d,%d,%d,%d) bounds=(%d,%d,%d,%d)",
1297 absBox.x(), absBox.y(), absBox.width(), absBox.height(),
1298 bounds.x(), bounds.y(), bounds.width(), bounds.height());
1301 DBG_NAV_LOGD("updateFrameCache node=%p", node);
1305 void WebViewCore::updateFrameCache()
1307 if (!m_frameCacheOutOfDate) {
1308 DBG_NAV_LOG("!m_frameCacheOutOfDate");
1311 #ifdef ANDROID_INSTRUMENT
1312 TimeCounterAuto counter(TimeCounter::WebViewCoreBuildNavTimeCounter);
1314 m_frameCacheOutOfDate = false;
1316 m_now = SkTime::GetMSecs();
1318 m_temp = new CachedRoot();
1319 m_temp->init(m_mainFrame, &m_history);
1320 #if USE(ACCELERATED_COMPOSITING)
1321 GraphicsLayerAndroid* graphicsLayer = graphicsRootLayer();
1323 m_temp->setRootLayer(graphicsLayer->contentLayer());
1325 CacheBuilder& builder = cacheBuilder();
1326 WebCore::Settings* settings = m_mainFrame->page()->settings();
1327 builder.allowAllTextDetection();
1328 #ifdef ANDROID_META_SUPPORT
1330 if (!settings->formatDetectionAddress())
1331 builder.disallowAddressDetection();
1332 if (!settings->formatDetectionEmail())
1333 builder.disallowEmailDetection();
1334 if (!settings->formatDetectionTelephone())
1335 builder.disallowPhoneDetection();
1338 builder.buildCache(m_temp);
1339 m_tempPict = new SkPicture();
1340 recordPicture(m_tempPict);
1341 m_temp->setPicture(m_tempPict);
1342 m_temp->setTextGeneration(m_textGeneration);
1343 WebCoreViewBridge* window = m_mainFrame->view()->platformWidget();
1344 m_temp->setVisibleRect(WebCore::IntRect(m_scrollOffsetX,
1345 m_scrollOffsetY, window->width(), window->height()));
1346 gFrameCacheMutex.lock();
1347 delete m_frameCacheKit;
1348 delete m_navPictureKit;
1349 m_frameCacheKit = m_temp;
1350 m_navPictureKit = m_tempPict;
1351 m_updatedFrameCache = true;
1353 const CachedNode* cachedFocusNode = m_frameCacheKit->currentFocus();
1354 DBG_NAV_LOGD("cachedFocusNode=%d (nodePointer=%p)",
1355 cachedFocusNode ? cachedFocusNode->index() : 0,
1356 cachedFocusNode ? cachedFocusNode->nodePointer() : 0);
1358 gFrameCacheMutex.unlock();
1361 void WebViewCore::updateFrameCacheIfLoading()
1363 if (!m_check_domtree_version)
1367 struct TouchNodeData {
1372 // get the bounding box of the Node
1373 static IntRect getAbsoluteBoundingBox(Node* node) {
1375 RenderObject* render = node->renderer();
1376 if (render->isRenderInline())
1377 rect = toRenderInline(render)->linesVisibleOverflowBoundingBox();
1378 else if (render->isBox())
1379 rect = toRenderBox(render)->visualOverflowRect();
1380 else if (render->isText())
1381 rect = toRenderText(render)->linesBoundingBox();
1383 LOGE("getAbsoluteBoundingBox failed for node %p, name %s", node, render->renderName());
1384 FloatPoint absPos = render->localToAbsolute();
1385 rect.move(absPos.x(), absPos.y());
1389 // get the highlight rectangles for the touch point (x, y) with the slop
1390 Vector<IntRect> WebViewCore::getTouchHighlightRects(int x, int y, int slop)
1392 Vector<IntRect> rects;
1393 m_mousePos = IntPoint(x - m_scrollOffsetX, y - m_scrollOffsetY);
1394 #ifdef ANDROID_HITTEST_WITHSIZE
1395 HitTestResult hitTestResult = m_mainFrame->eventHandler()->hitTestResultAtPoint(IntPoint(x, y),
1396 false, false, DontHitTestScrollbars, IntSize(slop, slop));
1397 if (!hitTestResult.innerNode() || !hitTestResult.innerNode()->inDocument()) {
1398 LOGE("Should not happen: no in document Node found");
1401 const Vector<RefPtr<Node> >& list = hitTestResult.rawNodeList();
1402 if (list.isEmpty()) {
1403 LOGE("Should not happen: no raw node found");
1406 Frame* frame = hitTestResult.innerNode()->document()->frame();
1407 Vector<TouchNodeData> nodeDataList;
1408 Vector<RefPtr<Node> >::const_iterator last = list.end();
1409 for (Vector<RefPtr<Node> >::const_iterator it = list.begin(); it != last; ++it) {
1410 // TODO: it seems reasonable to not search across the frame. Isn't it?
1411 // if the node is not in the same frame as the innerNode, skip it
1412 if (it->get()->document()->frame() != frame)
1414 // traverse up the tree to find the first node that needs highlight
1416 Node* eventNode = it->get();
1418 RenderObject* render = eventNode->renderer();
1419 if (render->isBody() || render->isRenderView())
1421 if (eventNode->supportsFocus()
1422 || eventNode->hasEventListeners(eventNames().clickEvent)
1423 || eventNode->hasEventListeners(eventNames().mousedownEvent)
1424 || eventNode->hasEventListeners(eventNames().mouseupEvent)) {
1428 // the nodes in the rawNodeList() are ordered based on z-index during hit testing.
1429 // so do not search for the eventNode across explicit z-index border.
1430 // TODO: this is a hard one to call. z-index is quite complicated as its value only
1431 // matters when you compare two RenderLayer in the same hierarchy level. e.g. in
1432 // the following example, "b" is on the top as its z level is the highest. even "c"
1433 // has 100 as z-index, it is still below "d" as its parent has the same z-index as
1434 // "d" and logically before "d". Of course "a" is the lowest in the z level.
1442 // If the fat point touches everyone, the order in the list should be "b", "d", "c"
1443 // and "a". When we search for the event node for "b", we really don't want "a" as
1444 // in the z-order it is behind everything else.
1445 if (!render->style()->hasAutoZIndex())
1447 eventNode = eventNode->parentNode();
1449 // didn't find any eventNode, skip it
1452 // first quick check whether it is a duplicated node before computing bounding box
1453 Vector<TouchNodeData>::const_iterator nlast = nodeDataList.end();
1454 for (Vector<TouchNodeData>::const_iterator n = nodeDataList.begin(); n != nlast; ++n) {
1455 // found the same node, skip it
1456 if (eventNode == n->mNode) {
1463 // next check whether the node is fully covered by or fully covering another node.
1465 IntRect rect = getAbsoluteBoundingBox(eventNode);
1466 if (rect.isEmpty()) {
1467 // if the node's bounds is empty and it is not a ContainerNode, skip it.
1468 if (!eventNode->isContainerNode())
1470 // if the node's children are all positioned objects, its bounds can be empty.
1471 // Walk through the children to find the bounding box.
1472 Node* child = static_cast<const ContainerNode*>(eventNode)->firstChild();
1475 if (child->renderer())
1476 childrect = getAbsoluteBoundingBox(child);
1477 if (!childrect.isEmpty()) {
1478 rect.unite(childrect);
1479 child = child->traverseNextSibling(eventNode);
1481 child = child->traverseNextNode(eventNode);
1484 for (int i = nodeDataList.size() - 1; i >= 0; i--) {
1485 TouchNodeData n = nodeDataList.at(i);
1486 // the new node is enclosing an existing node, skip it
1487 if (rect.contains(n.mBounds)) {
1491 // the new node is fully inside an existing node, remove the existing node
1492 if (n.mBounds.contains(rect))
1493 nodeDataList.remove(i);
1496 TouchNodeData newNode;
1497 newNode.mNode = eventNode;
1498 newNode.mBounds = rect;
1499 nodeDataList.append(newNode);
1502 if (!nodeDataList.size())
1504 // finally select the node with the largest overlap with the fat point
1505 TouchNodeData final;
1507 IntPoint docPos = frame->view()->windowToContents(m_mousePos);
1508 IntRect testRect(docPos.x() - slop, docPos.y() - slop, 2 * slop + 1, 2 * slop + 1);
1510 Vector<TouchNodeData>::const_iterator nlast = nodeDataList.end();
1511 for (Vector<TouchNodeData>::const_iterator n = nodeDataList.begin(); n != nlast; ++n) {
1512 IntRect rect = n->mBounds;
1513 rect.intersect(testRect);
1514 int a = rect.width() * rect.height();
1520 // now get the node's highlight rectangles in the page coordinate system
1522 IntPoint frameAdjust;
1523 if (frame != m_mainFrame) {
1524 frameAdjust = frame->view()->contentsToWindow(IntPoint());
1525 frameAdjust.move(m_scrollOffsetX, m_scrollOffsetY);
1527 if (final.mNode->isLink()) {
1528 // most of the links are inline instead of box style. So the bounding box is not
1529 // a good representation for the highlights. Get the list of rectangles instead.
1530 RenderObject* render = final.mNode->renderer();
1531 IntPoint offset = roundedIntPoint(render->localToAbsolute());
1532 render->absoluteRects(rects, offset.x() + frameAdjust.x(), offset.y() + frameAdjust.y());
1533 bool inside = false;
1534 int distance = INT_MAX;
1535 int newx = x, newy = y;
1536 int i = rects.size();
1538 if (rects[i].isEmpty()) {
1542 // check whether the point (x, y) is inside one of the rectangles.
1545 if (rects[i].contains(x, y)) {
1549 if (x >= rects[i].x() && x < rects[i].right()) {
1550 if (y < rects[i].y()) {
1551 if (rects[i].y() - y < distance) {
1553 newy = rects[i].y();
1554 distance = rects[i].y() - y;
1556 } else if (y >= rects[i].bottom()) {
1557 if (y - rects[i].bottom() + 1 < distance) {
1559 newy = rects[i].bottom() - 1;
1560 distance = y - rects[i].bottom() + 1;
1563 } else if (y >= rects[i].y() && y < rects[i].bottom()) {
1564 if (x < rects[i].x()) {
1565 if (rects[i].x() - x < distance) {
1566 newx = rects[i].x();
1568 distance = rects[i].x() - x;
1570 } else if (x >= rects[i].right()) {
1571 if (x - rects[i].right() + 1 < distance) {
1572 newx = rects[i].right() - 1;
1574 distance = x - rects[i].right() + 1;
1579 if (!rects.isEmpty()) {
1581 // if neither x nor y has overlap, just pick the top/left of the first rectangle
1582 if (newx == x && newy == y) {
1583 newx = rects[0].x();
1584 newy = rects[0].y();
1586 m_mousePos.setX(newx - m_scrollOffsetX);
1587 m_mousePos.setY(newy - m_scrollOffsetY);
1588 DBG_NAV_LOGD("Move x/y from (%d, %d) to (%d, %d) scrollOffset is (%d, %d)",
1589 x, y, m_mousePos.x() + m_scrollOffsetX, m_mousePos.y() + m_scrollOffsetY,
1590 m_scrollOffsetX, m_scrollOffsetY);
1595 IntRect rect = final.mBounds;
1596 rect.move(frameAdjust.x(), frameAdjust.y());
1598 // adjust m_mousePos if it is not inside the returned highlight rectangle
1599 testRect.move(frameAdjust.x(), frameAdjust.y());
1600 testRect.intersect(rect);
1601 if (!testRect.contains(x, y)) {
1602 m_mousePos = testRect.center();
1603 m_mousePos.move(-m_scrollOffsetX, -m_scrollOffsetY);
1604 DBG_NAV_LOGD("Move x/y from (%d, %d) to (%d, %d) scrollOffset is (%d, %d)",
1605 x, y, m_mousePos.x() + m_scrollOffsetX, m_mousePos.y() + m_scrollOffsetY,
1606 m_scrollOffsetX, m_scrollOffsetY);
1613 ///////////////////////////////////////////////////////////////////////////////
1615 void WebViewCore::addPlugin(PluginWidgetAndroid* w)
1617 // SkDebugf("----------- addPlugin %p", w);
1618 /* The plugin must be appended to the end of the array. This ensures that if
1619 the plugin is added while iterating through the array (e.g. sendEvent(...))
1620 that the iteration process is not corrupted.
1622 *m_plugins.append() = w;
1625 void WebViewCore::removePlugin(PluginWidgetAndroid* w)
1627 // SkDebugf("----------- removePlugin %p", w);
1628 int index = m_plugins.find(w);
1630 SkDebugf("--------------- pluginwindow not found! %p\n", w);
1632 m_plugins.removeShuffle(index);
1636 bool WebViewCore::isPlugin(PluginWidgetAndroid* w) const
1638 return m_plugins.find(w) >= 0;
1641 void WebViewCore::invalPlugin(PluginWidgetAndroid* w)
1643 const double PLUGIN_INVAL_DELAY = 1.0 / 60;
1645 if (!m_pluginInvalTimer.isActive()) {
1646 m_pluginInvalTimer.startOneShot(PLUGIN_INVAL_DELAY);
1650 void WebViewCore::drawPlugins()
1652 SkRegion inval; // accumualte what needs to be redrawn
1653 PluginWidgetAndroid** iter = m_plugins.begin();
1654 PluginWidgetAndroid** stop = m_plugins.end();
1656 for (; iter < stop; ++iter) {
1657 PluginWidgetAndroid* w = *iter;
1659 if (w->isDirty(&dirty)) {
1661 inval.op(dirty, SkRegion::kUnion_Op);
1665 if (!inval.isEmpty()) {
1666 // inval.getBounds() is our rectangle
1667 const SkIRect& bounds = inval.getBounds();
1668 WebCore::IntRect r(bounds.fLeft, bounds.fTop,
1669 bounds.width(), bounds.height());
1670 this->viewInvalidate(r);
1674 void WebViewCore::notifyPluginsOnFrameLoad(const Frame* frame) {
1675 // if frame is the parent then notify all plugins
1676 if (!frame->tree()->parent()) {
1677 // trigger an event notifying the plugins that the page has loaded
1679 SkANP::InitEvent(&event, kLifecycle_ANPEventType);
1680 event.data.lifecycle.action = kOnLoad_ANPLifecycleAction;
1681 sendPluginEvent(event);
1683 // else if frame's parent has completed
1684 else if (!frame->tree()->parent()->loader()->isLoading()) {
1685 // send to all plugins who have this frame in their heirarchy
1686 PluginWidgetAndroid** iter = m_plugins.begin();
1687 PluginWidgetAndroid** stop = m_plugins.end();
1688 for (; iter < stop; ++iter) {
1689 Frame* currentFrame = (*iter)->pluginView()->parentFrame();
1690 while (currentFrame) {
1691 if (frame == currentFrame) {
1693 SkANP::InitEvent(&event, kLifecycle_ANPEventType);
1694 event.data.lifecycle.action = kOnLoad_ANPLifecycleAction;
1695 (*iter)->sendEvent(event);
1698 currentFrame = currentFrame->tree()->parent();
1704 void WebViewCore::sendPluginVisibleScreen()
1706 /* We may want to cache the previous values and only send the notification
1707 to the plugin in the event that one of the values has changed.
1710 ANPRectI visibleRect;
1711 visibleRect.left = m_scrollOffsetX;
1712 visibleRect.top = m_scrollOffsetY;
1713 visibleRect.right = m_scrollOffsetX + m_screenWidth;
1714 visibleRect.bottom = m_scrollOffsetY + m_screenHeight;
1716 PluginWidgetAndroid** iter = m_plugins.begin();
1717 PluginWidgetAndroid** stop = m_plugins.end();
1718 for (; iter < stop; ++iter) {
1719 (*iter)->setVisibleScreen(visibleRect, m_scale);
1723 void WebViewCore::sendPluginEvent(const ANPEvent& evt)
1725 /* The list of plugins may be manipulated as we iterate through the list.
1726 This implementation allows for the addition of new plugins during an
1727 iteration, but may fail if a plugin is removed. Currently, there are not
1728 any use cases where a plugin is deleted while processing this loop, but
1729 if it does occur we will have to use an alternate data structure and/or
1730 iteration mechanism.
1732 for (int x = 0; x < m_plugins.count(); x++) {
1733 m_plugins[x]->sendEvent(evt);
1737 PluginWidgetAndroid* WebViewCore::getPluginWidget(NPP npp)
1739 PluginWidgetAndroid** iter = m_plugins.begin();
1740 PluginWidgetAndroid** stop = m_plugins.end();
1741 for (; iter < stop; ++iter) {
1742 if ((*iter)->pluginView()->instance() == npp) {
1749 static PluginView* nodeIsPlugin(Node* node) {
1750 RenderObject* renderer = node->renderer();
1751 if (renderer && renderer->isWidget()) {
1752 Widget* widget = static_cast<RenderWidget*>(renderer)->widget();
1753 if (widget && widget->isPluginView())
1754 return static_cast<PluginView*>(widget);
1759 Node* WebViewCore::cursorNodeIsPlugin() {
1760 gCursorBoundsMutex.lock();
1761 bool hasCursorBounds = m_hasCursorBounds;
1762 Frame* frame = (Frame*) m_cursorFrame;
1763 Node* node = (Node*) m_cursorNode;
1764 gCursorBoundsMutex.unlock();
1765 if (hasCursorBounds && CacheBuilder::validNode(m_mainFrame, frame, node)
1766 && nodeIsPlugin(node)) {
1772 ///////////////////////////////////////////////////////////////////////////////
1773 void WebViewCore::moveMouseIfLatest(int moveGeneration,
1774 WebCore::Frame* frame, int x, int y)
1776 DBG_NAV_LOGD("m_moveGeneration=%d moveGeneration=%d"
1777 " frame=%p x=%d y=%d",
1778 m_moveGeneration, moveGeneration, frame, x, y);
1779 if (m_moveGeneration > moveGeneration) {
1780 DBG_NAV_LOGD("m_moveGeneration=%d > moveGeneration=%d",
1781 m_moveGeneration, moveGeneration);
1782 return; // short-circuit if a newer move has already been generated
1784 m_lastGeneration = moveGeneration;
1785 moveMouse(frame, x, y);
1788 void WebViewCore::moveFocus(WebCore::Frame* frame, WebCore::Node* node)
1790 DBG_NAV_LOGD("frame=%p node=%p", frame, node);
1791 if (!node || !CacheBuilder::validNode(m_mainFrame, frame, node)
1792 || !node->isElementNode())
1794 // Code borrowed from FocusController::advanceFocus
1795 WebCore::FocusController* focusController
1796 = m_mainFrame->page()->focusController();
1797 WebCore::Document* oldDoc
1798 = focusController->focusedOrMainFrame()->document();
1799 if (oldDoc->focusedNode() == node)
1801 if (node->document() != oldDoc)
1802 oldDoc->setFocusedNode(0);
1803 focusController->setFocusedFrame(frame);
1804 static_cast<WebCore::Element*>(node)->focus(false);
1807 // Update mouse position
1808 void WebViewCore::moveMouse(WebCore::Frame* frame, int x, int y)
1810 DBG_NAV_LOGD("frame=%p x=%d y=%d scrollOffset=(%d,%d)", frame,
1811 x, y, m_scrollOffsetX, m_scrollOffsetY);
1812 if (!frame || CacheBuilder::validNode(m_mainFrame, frame, NULL) == false)
1813 frame = m_mainFrame;
1814 // mouse event expects the position in the window coordinate
1815 m_mousePos = WebCore::IntPoint(x - m_scrollOffsetX, y - m_scrollOffsetY);
1816 // validNode will still return true if the node is null, as long as we have
1817 // a valid frame. Do not want to make a call on frame unless it is valid.
1818 WebCore::PlatformMouseEvent mouseEvent(m_mousePos, m_mousePos,
1819 WebCore::NoButton, WebCore::MouseEventMoved, 1, false, false, false,
1820 false, WTF::currentTime());
1821 frame->eventHandler()->handleMouseMoveEvent(mouseEvent);
1822 updateCacheOnNodeChange();
1825 void WebViewCore::setSelection(int start, int end)
1827 WebCore::Node* focus = currentFocus();
1830 WebCore::RenderObject* renderer = focus->renderer();
1831 if (!renderer || (!renderer->isTextField() && !renderer->isTextArea()))
1833 WebCore::RenderTextControl* rtc = static_cast<WebCore::RenderTextControl*>(renderer);
1839 // Tell our EditorClient that this change was generated from the UI, so it
1840 // does not need to echo it to the UI.
1841 EditorClientAndroid* client = static_cast<EditorClientAndroid*>(
1842 m_mainFrame->editor()->client());
1843 client->setUiGeneratedSelectionChange(true);
1844 rtc->setSelectionRange(start, end);
1845 client->setUiGeneratedSelectionChange(false);
1846 WebCore::Frame* focusedFrame = focus->document()->frame();
1847 focusedFrame->revealSelection();
1848 setFocusControllerActive(focusedFrame, true);
1851 String WebViewCore::modifySelection(const String& alter, const String& direction, const String& granularity)
1853 DOMSelection* selection = m_mainFrame->domWindow()->getSelection();
1855 if (selection->rangeCount() == 0) {
1856 Document* document = m_mainFrame->document();
1857 HTMLElement* body = document->body();
1860 PassRefPtr<Range> rangeRef = document->createRange();
1861 rangeRef->setStart(PassRefPtr<Node>(body), 0, ec);
1863 LOGE("Error setting range start. Error code: %d", ec);
1867 rangeRef->setEnd(PassRefPtr<Node>(body), 0, ec);
1869 LOGE("Error setting range end. Error code: %d", ec);
1873 selection->addRange(rangeRef.get());
1876 if (equalIgnoringCase(direction, "forward")) {
1877 selection->collapseToEnd();
1878 } else if (equalIgnoringCase(direction, "backward")) {
1879 selection->collapseToStart();
1881 LOGE("Invalid direction: %s", direction.utf8().data());
1885 // NOTE: The selection of WebKit misbehaves and I need to add some
1886 // voodoo here to force it behave well. Rachel did something similar
1887 // in JS and I want to make sure it is optimal before adding it here.
1889 selection->modify(alter, direction, granularity);
1890 String selection_string = selection->toString();
1891 LOGD("Selection string: %s", selection_string.utf8().data());
1893 return selection_string;
1896 void WebViewCore::deleteSelection(int start, int end, int textGeneration)
1898 setSelection(start, end);
1901 WebCore::Node* focus = currentFocus();
1904 // Prevent our editor client from passing a message to change the
1906 EditorClientAndroid* client = static_cast<EditorClientAndroid*>(
1907 m_mainFrame->editor()->client());
1908 client->setUiGeneratedSelectionChange(true);
1909 PlatformKeyboardEvent down(kKeyCodeDel, 0, 0, true, false, false, false);
1910 PlatformKeyboardEvent up(kKeyCodeDel, 0, 0, false, false, false, false);
1913 client->setUiGeneratedSelectionChange(false);
1914 m_textGeneration = textGeneration;
1917 void WebViewCore::replaceTextfieldText(int oldStart,
1918 int oldEnd, const WebCore::String& replace, int start, int end,
1921 WebCore::Node* focus = currentFocus();
1924 setSelection(oldStart, oldEnd);
1925 // Prevent our editor client from passing a message to change the
1927 EditorClientAndroid* client = static_cast<EditorClientAndroid*>(
1928 m_mainFrame->editor()->client());
1929 client->setUiGeneratedSelectionChange(true);
1930 WebCore::TypingCommand::insertText(focus->document(), replace,
1932 client->setUiGeneratedSelectionChange(false);
1933 setSelection(start, end);
1934 m_textGeneration = textGeneration;
1937 void WebViewCore::passToJs(int generation, const WebCore::String& current,
1938 const PlatformKeyboardEvent& event)
1940 WebCore::Node* focus = currentFocus();
1942 DBG_NAV_LOG("!focus");
1946 WebCore::RenderObject* renderer = focus->renderer();
1947 if (!renderer || (!renderer->isTextField() && !renderer->isTextArea())) {
1948 DBG_NAV_LOGD("renderer==%p || not text", renderer);
1952 // Block text field updates during a key press.
1953 m_blockTextfieldUpdates = true;
1954 // Also prevent our editor client from passing a message to change the
1956 EditorClientAndroid* client = static_cast<EditorClientAndroid*>(
1957 m_mainFrame->editor()->client());
1958 client->setUiGeneratedSelectionChange(true);
1960 client->setUiGeneratedSelectionChange(false);
1961 m_blockTextfieldUpdates = false;
1962 m_textGeneration = generation;
1963 setFocusControllerActive(focus->document()->frame(), true);
1964 WebCore::RenderTextControl* renderText =
1965 static_cast<WebCore::RenderTextControl*>(renderer);
1966 WebCore::String test = renderText->text();
1967 if (test == current) {
1968 DBG_NAV_LOG("test == current");
1971 // If the text changed during the key event, update the UI text field.
1972 updateTextfield(focus, false, test);
1975 void WebViewCore::scrollFocusedTextInput(float xPercent, int y)
1977 WebCore::Node* focus = currentFocus();
1979 DBG_NAV_LOG("!focus");
1983 WebCore::RenderObject* renderer = focus->renderer();
1984 if (!renderer || (!renderer->isTextField() && !renderer->isTextArea())) {
1985 DBG_NAV_LOGD("renderer==%p || not text", renderer);
1989 WebCore::RenderTextControl* renderText =
1990 static_cast<WebCore::RenderTextControl*>(renderer);
1991 int x = (int) (xPercent * (renderText->scrollWidth() -
1992 renderText->clientWidth()));
1993 DBG_NAV_LOGD("x=%d y=%d xPercent=%g scrollW=%d clientW=%d", x, y,
1994 xPercent, renderText->scrollWidth(), renderText->clientWidth());
1995 renderText->setScrollLeft(x);
1996 renderText->setScrollTop(y);
1999 void WebViewCore::setFocusControllerActive(WebCore::Frame* frame, bool active)
2002 WebCore::Node* focus = currentFocus();
2004 frame = focus->document()->frame();
2006 frame = m_mainFrame;
2008 WebCore::FocusController* controller = frame->page()->focusController();
2009 controller->setActive(active);
2010 controller->setFocused(active);
2013 void WebViewCore::saveDocumentState(WebCore::Frame* frame)
2015 if (!CacheBuilder::validNode(m_mainFrame, frame, 0))
2016 frame = m_mainFrame;
2017 WebCore::HistoryItem *item = frame->loader()->history()->currentItem();
2019 // item can be null when there is no offical URL for the current page. This happens
2020 // when the content is loaded using with WebCoreFrameBridge::LoadData() and there
2021 // is no failing URL (common case is when content is loaded using data: scheme)
2023 item->setDocumentState(frame->document()->formElementsState());
2027 // Convert a WebCore::String into an array of characters where the first
2028 // character represents the length, for easy conversion to java.
2029 static uint16_t* stringConverter(const WebCore::String& text)
2031 size_t length = text.length();
2032 uint16_t* itemName = new uint16_t[length+1];
2033 itemName[0] = (uint16_t)length;
2034 uint16_t* firstChar = &(itemName[1]);
2035 memcpy((void*)firstChar, text.characters(), sizeof(UChar)*length);
2039 // Response to dropdown created for a listbox.
2040 class ListBoxReply : public WebCoreReply {
2042 ListBoxReply(WebCore::HTMLSelectElement* select, WebCore::Frame* frame, WebViewCore* view)
2048 // Response used if the listbox only allows single selection.
2049 // index is listIndex of the selected item, or -1 if nothing is selected.
2050 virtual void replyInt(int index)
2053 // Special value for cancel. Do nothing.
2056 // If the select element no longer exists, due to a page change, etc,
2058 if (!m_select || !CacheBuilder::validNode(m_viewImpl->m_mainFrame,
2061 // Use a pointer to HTMLSelectElement's superclass, where
2062 // listToOptionIndex is public.
2063 SelectElement* selectElement = m_select;
2064 int optionIndex = selectElement->listToOptionIndex(index);
2065 m_select->setSelectedIndex(optionIndex, true);
2066 m_select->dispatchFormControlChangeEvent();
2067 m_viewImpl->contentInvalidate(m_select->getRect());
2070 // Response if the listbox allows multiple selection. array stores the listIndices
2071 // of selected positions.
2072 virtual void replyIntArray(const int* array, int count)
2074 // If the select element no longer exists, due to a page change, etc,
2076 if (!m_select || !CacheBuilder::validNode(m_viewImpl->m_mainFrame,
2080 // If count is 1 or 0, use replyInt.
2081 SkASSERT(count > 1);
2083 const WTF::Vector<Element*>& items = m_select->listItems();
2084 int totalItems = static_cast<int>(items.size());
2085 // Keep track of the position of the value we are comparing against.
2087 // The value we are comparing against.
2088 int selection = array[arrayIndex];
2089 WebCore::HTMLOptionElement* option;
2090 for (int listIndex = 0; listIndex < totalItems; listIndex++) {
2091 if (items[listIndex]->hasLocalName(WebCore::HTMLNames::optionTag)) {
2092 option = static_cast<WebCore::HTMLOptionElement*>(
2094 if (listIndex == selection) {
2095 option->setSelectedState(true);
2097 if (arrayIndex == count)
2100 selection = array[arrayIndex];
2102 option->setSelectedState(false);
2105 m_select->dispatchFormControlChangeEvent();
2106 m_viewImpl->contentInvalidate(m_select->getRect());
2109 // The select element associated with this listbox.
2110 WebCore::HTMLSelectElement* m_select;
2111 // The frame of this select element, to verify that it is valid.
2112 WebCore::Frame* m_frame;
2113 // For calling invalidate and checking the select element's validity
2114 WebViewCore* m_viewImpl;
2117 // Create an array of java Strings.
2118 static jobjectArray makeLabelArray(JNIEnv* env, const uint16_t** labels, size_t count)
2120 jclass stringClass = env->FindClass("java/lang/String");
2121 LOG_ASSERT(stringClass, "Could not find java/lang/String");
2122 jobjectArray array = env->NewObjectArray(count, stringClass, 0);
2123 LOG_ASSERT(array, "Could not create new string array");
2125 for (size_t i = 0; i < count; i++) {
2126 jobject newString = env->NewString(&labels[i][1], labels[i][0]);
2127 env->SetObjectArrayElement(array, i, newString);
2128 env->DeleteLocalRef(newString);
2129 checkException(env);
2131 env->DeleteLocalRef(stringClass);
2135 void WebViewCore::openFileChooser(PassRefPtr<WebCore::FileChooser> chooser) {
2138 JNIEnv* env = JSC::Bindings::getJNIEnv();
2140 WebCore::String acceptType = chooser->acceptTypes();
2141 jstring jAcceptType = env->NewString(const_cast<unsigned short*>(acceptType.characters()), acceptType.length());
2142 jstring jName = (jstring) env->CallObjectMethod(
2143 m_javaGlue->object(env).get(), m_javaGlue->m_openFileChooser, jAcceptType);
2144 checkException(env);
2145 env->DeleteLocalRef(jAcceptType);
2147 const UChar* string = static_cast<const UChar*>(env->GetStringChars(jName, NULL));
2152 WebCore::String webcoreString = to_string(env, jName);
2153 env->ReleaseStringChars(jName, string);
2155 if (webcoreString.length())
2156 chooser->chooseFile(webcoreString);
2159 void WebViewCore::listBoxRequest(WebCoreReply* reply, const uint16_t** labels, size_t count, const int enabled[], size_t enabledCount,
2160 bool multiple, const int selected[], size_t selectedCountOrSelection)
2162 // If m_popupReply is not null, then we already have a list showing.
2163 if (m_popupReply != 0)
2166 LOG_ASSERT(m_javaGlue->m_obj, "No java widget associated with this view!");
2168 // Create an array of java Strings for the drop down.
2169 JNIEnv* env = JSC::Bindings::getJNIEnv();
2170 jobjectArray labelArray = makeLabelArray(env, labels, count);
2172 // Create an array determining whether each item is enabled.
2173 jintArray enabledArray = env->NewIntArray(enabledCount);
2174 checkException(env);
2175 jint* ptrArray = env->GetIntArrayElements(enabledArray, 0);
2176 checkException(env);
2177 for (size_t i = 0; i < enabledCount; i++) {
2178 ptrArray[i] = enabled[i];
2180 env->ReleaseIntArrayElements(enabledArray, ptrArray, 0);
2181 checkException(env);
2184 // Pass up an array representing which items are selected.
2185 jintArray selectedArray = env->NewIntArray(selectedCountOrSelection);
2186 checkException(env);
2187 jint* selArray = env->GetIntArrayElements(selectedArray, 0);
2188 checkException(env);
2189 for (size_t i = 0; i < selectedCountOrSelection; i++) {
2190 selArray[i] = selected[i];
2192 env->ReleaseIntArrayElements(selectedArray, selArray, 0);
2194 env->CallVoidMethod(m_javaGlue->object(env).get(),
2195 m_javaGlue->m_requestListBox, labelArray, enabledArray,
2197 env->DeleteLocalRef(selectedArray);
2199 // Pass up the single selection.
2200 env->CallVoidMethod(m_javaGlue->object(env).get(),
2201 m_javaGlue->m_requestSingleListBox, labelArray, enabledArray,
2202 selectedCountOrSelection);
2205 env->DeleteLocalRef(labelArray);
2206 env->DeleteLocalRef(enabledArray);
2207 checkException(env);
2210 m_popupReply = reply;
2213 bool WebViewCore::key(const PlatformKeyboardEvent& event)
2215 WebCore::EventHandler* eventHandler;
2216 WebCore::Node* focusNode = currentFocus();
2217 DBG_NAV_LOGD("keyCode=%s unichar=%d focusNode=%p",
2218 event.keyIdentifier().utf8().data(), event.unichar(), focusNode);
2220 WebCore::Frame* frame = focusNode->document()->frame();
2221 eventHandler = frame->eventHandler();
2222 if (focusNode->isContentEditable()) {
2223 // keyEvent will return true even if the contentEditable did not
2224 // change its selection. In the case that it does not, we want to
2225 // return false so that the key will be sent back to our navigation
2227 VisibleSelection old = frame->selection()->selection();
2228 eventHandler->keyEvent(event);
2229 return frame->selection()->selection() != old;
2232 eventHandler = m_mainFrame->eventHandler();
2234 return eventHandler->keyEvent(event);
2237 // For when the user clicks the trackball
2238 void WebViewCore::click(WebCore::Frame* frame, WebCore::Node* node) {
2240 WebCore::IntPoint pt = m_mousePos;
2241 pt.move(m_scrollOffsetX, m_scrollOffsetY);
2242 WebCore::HitTestResult hitTestResult = m_mainFrame->eventHandler()->
2243 hitTestResultAtPoint(pt, false);
2244 node = hitTestResult.innerNode();
2245 frame = node->document()->frame();
2246 DBG_NAV_LOGD("m_mousePos=(%d,%d) m_scrollOffset=(%d,%d) pt=(%d,%d)"
2247 " node=%p", m_mousePos.x(), m_mousePos.y(),
2248 m_scrollOffsetX, m_scrollOffsetY, pt.x(), pt.y(), node);
2251 EditorClientAndroid* client
2252 = static_cast<EditorClientAndroid*>(
2253 m_mainFrame->editor()->client());
2254 client->setShouldChangeSelectedRange(false);
2255 handleMouseClick(frame, node);
2256 client->setShouldChangeSelectedRange(true);
2260 #if USE(ACCELERATED_COMPOSITING)
2261 GraphicsLayerAndroid* WebViewCore::graphicsRootLayer() const
2263 RenderView* contentRenderer = m_mainFrame->contentRenderer();
2264 if (!contentRenderer)
2266 return static_cast<GraphicsLayerAndroid*>(
2267 contentRenderer->compositor()->rootPlatformLayer());
2271 bool WebViewCore::handleTouchEvent(int action, int x, int y, int metaState)
2273 bool preventDefault = false;
2275 #if USE(ACCELERATED_COMPOSITING)
2276 GraphicsLayerAndroid* rootLayer = graphicsRootLayer();
2278 rootLayer->pauseDisplay(true);
2281 #if ENABLE(TOUCH_EVENTS) // Android
2282 WebCore::TouchEventType type = WebCore::TouchStart;
2283 WebCore::PlatformTouchPoint::State touchState = WebCore::PlatformTouchPoint::TouchPressed;
2285 case 0: // MotionEvent.ACTION_DOWN
2286 type = WebCore::TouchStart;
2288 case 1: // MotionEvent.ACTION_UP
2289 type = WebCore::TouchEnd;
2290 touchState = WebCore::PlatformTouchPoint::TouchReleased;
2292 case 2: // MotionEvent.ACTION_MOVE
2293 type = WebCore::TouchMove;
2294 touchState = WebCore::PlatformTouchPoint::TouchMoved;
2296 case 3: // MotionEvent.ACTION_CANCEL
2297 type = WebCore::TouchCancel;
2298 touchState = WebCore::PlatformTouchPoint::TouchCancelled;
2300 case 0x100: // WebViewCore.ACTION_LONGPRESS
2301 type = WebCore::TouchLongPress;
2302 touchState = WebCore::PlatformTouchPoint::TouchPressed;
2304 case 0x200: // WebViewCore.ACTION_DOUBLETAP
2305 type = WebCore::TouchDoubleTap;
2306 touchState = WebCore::PlatformTouchPoint::TouchPressed;
2309 // We do not support other kinds of touch event inside WebCore
2311 LOGW("Java passed a touch event type that we do not support in WebCore: %d", action);
2315 // Track previous touch and if stationary set the state.
2316 WebCore::IntPoint pt(x - m_scrollOffsetX, y - m_scrollOffsetY);
2318 WebCore::PlatformTouchEvent te(pt, type, touchState, metaState);
2319 preventDefault = m_mainFrame->eventHandler()->handleTouchEvent(te);
2322 #if USE(ACCELERATED_COMPOSITING)
2324 rootLayer->pauseDisplay(false);
2326 return preventDefault;
2329 void WebViewCore::touchUp(int touchGeneration,
2330 WebCore::Frame* frame, WebCore::Node* node, int x, int y)
2332 if (touchGeneration == 0) {
2333 // m_mousePos should be set in getTouchHighlightRects()
2334 WebCore::HitTestResult hitTestResult = m_mainFrame->eventHandler()->hitTestResultAtPoint(m_mousePos, false);
2335 node = hitTestResult.innerNode();
2337 frame = node->document()->frame();
2340 DBG_NAV_LOGD("touch up on (%d, %d), scrollOffset is (%d, %d), node:%p, frame:%p", m_mousePos.x() + m_scrollOffsetX, m_mousePos.y() + m_scrollOffsetY, m_scrollOffsetX, m_scrollOffsetY, node, frame);
2342 if (m_touchGeneration > touchGeneration) {
2343 DBG_NAV_LOGD("m_touchGeneration=%d > touchGeneration=%d"
2344 " x=%d y=%d", m_touchGeneration, touchGeneration, x, y);
2345 return; // short circuit if a newer touch has been generated
2347 // This moves m_mousePos to the correct place, and handleMouseClick uses
2348 // m_mousePos to determine where the click happens.
2349 moveMouse(frame, x, y);
2350 m_lastGeneration = touchGeneration;
2352 if (frame && CacheBuilder::validNode(m_mainFrame, frame, 0)) {
2353 frame->loader()->resetMultipleFormSubmissionProtection();
2355 DBG_NAV_LOGD("touchGeneration=%d handleMouseClick frame=%p node=%p"
2356 " x=%d y=%d", touchGeneration, frame, node, x, y);
2357 handleMouseClick(frame, node);
2360 // Common code for both clicking with the trackball and touchUp
2361 bool WebViewCore::handleMouseClick(WebCore::Frame* framePtr, WebCore::Node* nodePtr)
2363 bool valid = framePtr == NULL
2364 || CacheBuilder::validNode(m_mainFrame, framePtr, nodePtr);
2365 WebFrame* webFrame = WebFrame::getWebFrame(m_mainFrame);
2366 if (valid && nodePtr) {
2367 // Need to special case area tags because an image map could have an area element in the middle
2368 // so when attempting to get the default, the point chosen would be follow the wrong link.
2369 if (nodePtr->hasTagName(WebCore::HTMLNames::areaTag)) {
2370 webFrame->setUserInitiatedClick(true);
2371 nodePtr->dispatchSimulatedClick(0, true, true);
2372 webFrame->setUserInitiatedClick(false);
2373 DBG_NAV_LOG("area");
2376 WebCore::RenderObject* renderer = nodePtr->renderer();
2377 if (renderer && (renderer->isMenuList() || renderer->isListBox())) {
2378 WebCore::HTMLSelectElement* select = static_cast<WebCore::HTMLSelectElement*>(nodePtr);
2379 const WTF::Vector<WebCore::Element*>& listItems = select->listItems();
2380 SkTDArray<const uint16_t*> names;
2381 // Possible values for enabledArray. Keep in Sync with values in
2382 // InvokeListBox.Container in WebView.java
2385 OPTION_DISABLED = 0,
2388 SkTDArray<int> enabledArray;
2389 SkTDArray<int> selectedArray;
2390 int size = listItems.size();
2391 bool multiple = select->multiple();
2392 for (int i = 0; i < size; i++) {
2393 if (listItems[i]->hasTagName(WebCore::HTMLNames::optionTag)) {
2394 WebCore::HTMLOptionElement* option = static_cast<WebCore::HTMLOptionElement*>(listItems[i]);
2395 *names.append() = stringConverter(option->textIndentedToRespectGroupLabel());
2396 *enabledArray.append() = option->disabled() ? OPTION_DISABLED : OPTION_ENABLED;
2397 if (multiple && option->selected())
2398 *selectedArray.append() = i;
2399 } else if (listItems[i]->hasTagName(WebCore::HTMLNames::optgroupTag)) {
2400 WebCore::HTMLOptGroupElement* optGroup = static_cast<WebCore::HTMLOptGroupElement*>(listItems[i]);
2401 *names.append() = stringConverter(optGroup->groupLabelText());
2402 *enabledArray.append() = OPTGROUP;
2405 WebCoreReply* reply = new ListBoxReply(select, select->document()->frame(), this);
2406 // Use a pointer to HTMLSelectElement's superclass, where
2407 // optionToListIndex is public.
2408 SelectElement* selectElement = select;
2409 listBoxRequest(reply, names.begin(), size, enabledArray.begin(), enabledArray.count(),
2410 multiple, selectedArray.begin(), multiple ? selectedArray.count() :
2411 selectElement->optionToListIndex(select->selectedIndex()));
2412 DBG_NAV_LOG("menu list");
2416 if (!valid || !framePtr)
2417 framePtr = m_mainFrame;
2418 webFrame->setUserInitiatedClick(true);
2419 WebCore::PlatformMouseEvent mouseDown(m_mousePos, m_mousePos, WebCore::LeftButton,
2420 WebCore::MouseEventPressed, 1, false, false, false, false,
2421 WTF::currentTime());
2422 // ignore the return from as it will return true if the hit point can trigger selection change
2423 framePtr->eventHandler()->handleMousePressEvent(mouseDown);
2424 WebCore::PlatformMouseEvent mouseUp(m_mousePos, m_mousePos, WebCore::LeftButton,
2425 WebCore::MouseEventReleased, 1, false, false, false, false,
2426 WTF::currentTime());
2427 bool handled = framePtr->eventHandler()->handleMouseReleaseEvent(mouseUp);
2428 webFrame->setUserInitiatedClick(false);
2430 // If the user clicked on a textfield, make the focusController active
2431 // so we show the blinking cursor.
2432 WebCore::Node* focusNode = currentFocus();
2433 DBG_NAV_LOGD("m_mousePos={%d,%d} focusNode=%p handled=%s", m_mousePos.x(),
2434 m_mousePos.y(), focusNode, handled ? "true" : "false");
2436 WebCore::RenderObject* renderer = focusNode->renderer();
2437 if (renderer && (renderer->isTextField() || renderer->isTextArea())) {
2438 bool ime = !(static_cast<WebCore::HTMLInputElement*>(focusNode))
2440 setFocusControllerActive(framePtr, ime);
2442 RenderTextControl* rtc
2443 = static_cast<RenderTextControl*> (renderer);
2444 requestKeyboardWithSelection(focusNode, rtc->selectionStart(),
2445 rtc->selectionEnd());
2447 requestKeyboard(false);
2449 } else if (focusNode->isContentEditable()) {
2450 setFocusControllerActive(framePtr, true);
2451 requestKeyboard(true);
2457 void WebViewCore::popupReply(int index)
2460 m_popupReply->replyInt(index);
2461 Release(m_popupReply);
2466 void WebViewCore::popupReply(const int* array, int count)
2469 m_popupReply->replyIntArray(array, count);
2470 Release(m_popupReply);
2471 m_popupReply = NULL;
2475 void WebViewCore::addMessageToConsole(const WebCore::String& message, unsigned int lineNumber, const WebCore::String& sourceID, int msgLevel) {
2476 JNIEnv* env = JSC::Bindings::getJNIEnv();
2477 jstring jMessageStr = env->NewString((unsigned short *)message.characters(), message.length());
2478 jstring jSourceIDStr = env->NewString((unsigned short *)sourceID.characters(), sourceID.length());
2479 env->CallVoidMethod(m_javaGlue->object(env).get(),
2480 m_javaGlue->m_addMessageToConsole, jMessageStr, lineNumber,
2481 jSourceIDStr, msgLevel);
2482 env->DeleteLocalRef(jMessageStr);
2483 env->DeleteLocalRef(jSourceIDStr);
2484 checkException(env);
2487 void WebViewCore::jsAlert(const WebCore::String& url, const WebCore::String& text)
2489 JNIEnv* env = JSC::Bindings::getJNIEnv();
2490 jstring jInputStr = env->NewString((unsigned short *)text.characters(), text.length());
2491 jstring jUrlStr = env->NewString((unsigned short *)url.characters(), url.length());
2492 env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_jsAlert, jUrlStr, jInputStr);
2493 env->DeleteLocalRef(jInputStr);
2494 env->DeleteLocalRef(jUrlStr);
2495 checkException(env);
2498 void WebViewCore::exceededDatabaseQuota(const WebCore::String& url, const WebCore::String& databaseIdentifier, const unsigned long long currentQuota, unsigned long long estimatedSize)
2500 #if ENABLE(DATABASE)
2501 JNIEnv* env = JSC::Bindings::getJNIEnv();
2502 jstring jDatabaseIdentifierStr = env->NewString((unsigned short *)databaseIdentifier.characters(), databaseIdentifier.length());
2503 jstring jUrlStr = env->NewString((unsigned short *)url.characters(), url.length());
2504 env->CallVoidMethod(m_javaGlue->object(env).get(),
2505 m_javaGlue->m_exceededDatabaseQuota, jUrlStr,
2506 jDatabaseIdentifierStr, currentQuota, estimatedSize);
2507 env->DeleteLocalRef(jDatabaseIdentifierStr);
2508 env->DeleteLocalRef(jUrlStr);
2509 checkException(env);
2513 void WebViewCore::reachedMaxAppCacheSize(const unsigned long long spaceNeeded)
2515 #if ENABLE(OFFLINE_WEB_APPLICATIONS)
2516 JNIEnv* env = JSC::Bindings::getJNIEnv();
2517 env->CallVoidMethod(m_javaGlue->object(env).get(),
2518 m_javaGlue->m_reachedMaxAppCacheSize, spaceNeeded);
2519 checkException(env);
2523 void WebViewCore::populateVisitedLinks(WebCore::PageGroup* group)
2525 m_groupForVisitedLinks = group;
2526 JNIEnv* env = JSC::Bindings::getJNIEnv();
2527 env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_populateVisitedLinks);
2528 checkException(env);
2531 void WebViewCore::geolocationPermissionsShowPrompt(const WebCore::String& origin)
2533 JNIEnv* env = JSC::Bindings::getJNIEnv();
2534 jstring originString = env->NewString((unsigned short *)origin.characters(), origin.length());
2535 env->CallVoidMethod(m_javaGlue->object(env).get(),
2536 m_javaGlue->m_geolocationPermissionsShowPrompt,
2538 env->DeleteLocalRef(originString);
2539 checkException(env);
2542 void WebViewCore::geolocationPermissionsHidePrompt()
2544 JNIEnv* env = JSC::Bindings::getJNIEnv();
2545 env->CallVoidMethod(m_javaGlue->object(env).get(),
2546 m_javaGlue->m_geolocationPermissionsHidePrompt);
2547 checkException(env);
2550 bool WebViewCore::jsConfirm(const WebCore::String& url, const WebCore::String& text)
2552 JNIEnv* env = JSC::Bindings::getJNIEnv();
2553 jstring jInputStr = env->NewString((unsigned short *)text.characters(), text.length());
2554 jstring jUrlStr = env->NewString((unsigned short *)url.characters(), url.length());
2555 jboolean result = env->CallBooleanMethod(m_javaGlue->object(env).get(), m_javaGlue->m_jsConfirm, jUrlStr, jInputStr);
2556 env->DeleteLocalRef(jInputStr);
2557 env->DeleteLocalRef(jUrlStr);
2558 checkException(env);
2562 bool WebViewCore::jsPrompt(const WebCore::String& url, const WebCore::String& text, const WebCore::String& defaultValue, WebCore::String& result)
2564 JNIEnv* env = JSC::Bindings::getJNIEnv();
2565 jstring jInputStr = env->NewString((unsigned short *)text.characters(), text.length());
2566 jstring jDefaultStr = env->NewString((unsigned short *)defaultValue.characters(), defaultValue.length());
2567 jstring jUrlStr = env->NewString((unsigned short *)url.characters(), url.length());
2568 jstring returnVal = (jstring) env->CallObjectMethod(m_javaGlue->object(env).get(), m_javaGlue->m_jsPrompt, jUrlStr, jInputStr, jDefaultStr);
2569 // If returnVal is null, it means that the user cancelled the dialog.
2573 result = to_string(env, returnVal);
2574 env->DeleteLocalRef(jInputStr);
2575 env->DeleteLocalRef(jDefaultStr);
2576 env->DeleteLocalRef(jUrlStr);
2577 checkException(env);
2581 bool WebViewCore::jsUnload(const WebCore::String& url, const WebCore::String& message)
2583 JNIEnv* env = JSC::Bindings::getJNIEnv();
2584 jstring jInputStr = env->NewString((unsigned short *)message.characters(), message.length());
2585 jstring jUrlStr = env->NewString((unsigned short *)url.characters(), url.length());
2586 jboolean result = env->CallBooleanMethod(m_javaGlue->object(env).get(), m_javaGlue->m_jsUnload, jUrlStr, jInputStr);
2587 env->DeleteLocalRef(jInputStr);
2588 env->DeleteLocalRef(jUrlStr);
2589 checkException(env);
2593 bool WebViewCore::jsInterrupt()
2595 JNIEnv* env = JSC::Bindings::getJNIEnv();
2596 jboolean result = env->CallBooleanMethod(m_javaGlue->object(env).get(), m_javaGlue->m_jsInterrupt);
2597 checkException(env);
2602 WebViewCore::getJavaObject()
2604 return getRealObject(JSC::Bindings::getJNIEnv(), m_javaGlue->m_obj);
2608 WebViewCore::getWebViewJavaObject()
2610 JNIEnv* env = JSC::Bindings::getJNIEnv();
2611 return env->GetObjectField(m_javaGlue->object(env).get(), gWebViewCoreFields.m_webView);
2614 void WebViewCore::updateTextSelection() {
2615 WebCore::Node* focusNode = currentFocus();
2618 RenderObject* renderer = focusNode->renderer();
2619 if (!renderer || (!renderer->isTextArea() && !renderer->isTextField()))
2621 RenderTextControl* rtc = static_cast<RenderTextControl*>(renderer);
2622 JNIEnv* env = JSC::Bindings::getJNIEnv();
2623 env->CallVoidMethod(m_javaGlue->object(env).get(),
2624 m_javaGlue->m_updateTextSelection, reinterpret_cast<int>(focusNode),
2625 rtc->selectionStart(), rtc->selectionEnd(), m_textGeneration);
2626 checkException(env);
2629 void WebViewCore::updateTextfield(WebCore::Node* ptr, bool changeToPassword,
2630 const WebCore::String& text)
2632 if (m_blockTextfieldUpdates)
2634 JNIEnv* env = JSC::Bindings::getJNIEnv();
2635 if (changeToPassword) {
2636 env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_updateTextfield,
2637 (int) ptr, true, 0, m_textGeneration);
2638 checkException(env);
2641 int length = text.length();
2642 jstring string = env->NewString((unsigned short *) text.characters(), length);
2643 env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_updateTextfield,
2644 (int) ptr, false, string, m_textGeneration);
2645 env->DeleteLocalRef(string);
2646 checkException(env);
2649 void WebViewCore::clearTextEntry()
2651 JNIEnv* env = JSC::Bindings::getJNIEnv();
2652 env->CallVoidMethod(m_javaGlue->object(env).get(),
2653 m_javaGlue->m_clearTextEntry);
2656 void WebViewCore::setBackgroundColor(SkColor c)
2658 WebCore::FrameView* view = m_mainFrame->view();
2662 // need (int) cast to find the right constructor
2663 WebCore::Color bcolor((int)SkColorGetR(c), (int)SkColorGetG(c),
2664 (int)SkColorGetB(c), (int)SkColorGetA(c));
2665 view->setBaseBackgroundColor(bcolor);
2667 // Background color of 0 indicates we want a transparent background
2669 view->setTransparent(true);
2672 jclass WebViewCore::getPluginClass(const WebCore::String& libName, const char* className)
2674 JNIEnv* env = JSC::Bindings::getJNIEnv();
2676 jstring libString = env->NewString(libName.characters(), libName.length());
2677 jstring classString = env->NewStringUTF(className);
2678 jobject pluginClass = env->CallObjectMethod(m_javaGlue->object(env).get(),
2679 m_javaGlue->m_getPluginClass,
2680 libString, classString);
2681 checkException(env);
2683 // cleanup unneeded local JNI references
2684 env->DeleteLocalRef(libString);
2685 env->DeleteLocalRef(classString);
2687 if (pluginClass != NULL) {
2688 return static_cast<jclass>(pluginClass);
2694 void WebViewCore::showFullScreenPlugin(jobject childView, NPP npp)
2696 JNIEnv* env = JSC::Bindings::getJNIEnv();
2697 AutoJObject obj = m_javaGlue->object(env);
2699 env->CallVoidMethod(obj.get(),
2700 m_javaGlue->m_showFullScreenPlugin, childView, (int)npp);
2701 checkException(env);
2704 void WebViewCore::hideFullScreenPlugin()
2706 JNIEnv* env = JSC::Bindings::getJNIEnv();
2707 env->CallVoidMethod(m_javaGlue->object(env).get(),
2708 m_javaGlue->m_hideFullScreenPlugin);
2709 checkException(env);
2712 jobject WebViewCore::addSurface(jobject view, int x, int y, int width, int height)
2714 JNIEnv* env = JSC::Bindings::getJNIEnv();
2715 jobject result = env->CallObjectMethod(m_javaGlue->object(env).get(),
2716 m_javaGlue->m_addSurface,
2717 view, x, y, width, height);
2718 checkException(env);
2722 void WebViewCore::updateSurface(jobject childView, int x, int y, int width, int height)
2724 JNIEnv* env = JSC::Bindings::getJNIEnv();
2725 env->CallVoidMethod(m_javaGlue->object(env).get(),
2726 m_javaGlue->m_updateSurface, childView,
2727 x, y, width, height);
2728 checkException(env);
2731 void WebViewCore::destroySurface(jobject childView)
2733 JNIEnv* env = JSC::Bindings::getJNIEnv();
2734 env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_destroySurface, childView);
2735 checkException(env);
2738 jobject WebViewCore::getContext()
2740 JNIEnv* env = JSC::Bindings::getJNIEnv();
2741 AutoJObject obj = m_javaGlue->object(env);
2743 jobject result = env->CallObjectMethod(obj.get(), m_javaGlue->m_getContext);
2744 checkException(env);
2748 bool WebViewCore::validNodeAndBounds(Frame* frame, Node* node,
2749 const IntRect& originalAbsoluteBounds)
2751 bool valid = CacheBuilder::validNode(m_mainFrame, frame, node);
2754 RenderObject* renderer = node->renderer();
2757 IntRect absBounds = node->hasTagName(HTMLNames::areaTag)
2758 ? CacheBuilder::getAreaRect(static_cast<HTMLAreaElement*>(node))
2759 : renderer->absoluteBoundingBoxRect();
2760 return absBounds == originalAbsoluteBounds;
2763 void WebViewCore::showRect(int left, int top, int width, int height,
2764 int contentWidth, int contentHeight, float xPercentInDoc,
2765 float xPercentInView, float yPercentInDoc, float yPercentInView)
2767 JNIEnv* env = JSC::Bindings::getJNIEnv();
2768 env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_showRect,
2769 left, top, width, height, contentWidth, contentHeight,
2770 xPercentInDoc, xPercentInView, yPercentInDoc, yPercentInView);
2771 checkException(env);
2774 void WebViewCore::centerFitRect(int x, int y, int width, int height)
2776 JNIEnv* env = JSC::Bindings::getJNIEnv();
2777 env->CallVoidMethod(m_javaGlue->object(env).get(),
2778 m_javaGlue->m_centerFitRect, x, y, width, height);
2779 checkException(env);
2783 void WebViewCore::setScrollbarModes(ScrollbarMode horizontalMode, ScrollbarMode verticalMode)
2785 JNIEnv* env = JSC::Bindings::getJNIEnv();
2786 env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_setScrollbarModes,
2787 horizontalMode, verticalMode);
2788 checkException(env);
2791 void WebViewCore::notifyWebAppCanBeInstalled()
2793 JNIEnv* env = JSC::Bindings::getJNIEnv();
2794 env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_setInstallableWebApp);
2795 checkException(env);
2798 //----------------------------------------------------------------------
2799 // Native JNI methods
2800 //----------------------------------------------------------------------
2801 static jstring WebCoreStringToJString(JNIEnv *env, WebCore::String string)
2803 int length = string.length();
2806 jstring ret = env->NewString((jchar *)string.characters(), length);
2807 env->DeleteLocalRef(ret);
2811 static jstring RequestLabel(JNIEnv *env, jobject obj, int framePointer,
2814 return WebCoreStringToJString(env, GET_NATIVE_VIEW(env, obj)->requestLabel(
2815 (WebCore::Frame*) framePointer, (WebCore::Node*) nodePointer));
2818 static void UpdateFrameCacheIfLoading(JNIEnv *env, jobject obj)
2820 GET_NATIVE_VIEW(env, obj)->updateFrameCacheIfLoading();
2823 static void SetSize(JNIEnv *env, jobject obj, jint width, jint height,
2824 jint textWrapWidth, jfloat scale, jint screenWidth, jint screenHeight,
2825 jint anchorX, jint anchorY, jboolean ignoreHeight)
2827 #ifdef ANDROID_INSTRUMENT
2828 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
2830 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
2831 LOGV("webviewcore::nativeSetSize(%u %u)\n viewImpl: %p", (unsigned)width, (unsigned)height, viewImpl);
2832 LOG_ASSERT(viewImpl, "viewImpl not set in nativeSetSize");
2833 viewImpl->setSizeScreenWidthAndScale(width, height, textWrapWidth, scale,
2834 screenWidth, screenHeight, anchorX, anchorY, ignoreHeight);
2837 static void SetScrollOffset(JNIEnv *env, jobject obj, jint gen, jint x, jint y)
2839 #ifdef ANDROID_INSTRUMENT
2840 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
2842 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
2843 LOG_ASSERT(viewImpl, "need viewImpl");
2845 viewImpl->setScrollOffset(gen, x, y);
2848 static void SetGlobalBounds(JNIEnv *env, jobject obj, jint x, jint y, jint h,
2851 #ifdef ANDROID_INSTRUMENT
2852 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
2854 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
2855 LOG_ASSERT(viewImpl, "need viewImpl");
2857 viewImpl->setGlobalBounds(x, y, h, v);
2860 static jboolean Key(JNIEnv *env, jobject obj, jint keyCode, jint unichar,
2861 jint repeatCount, jboolean isShift, jboolean isAlt, jboolean isSym,
2864 #ifdef ANDROID_INSTRUMENT
2865 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
2867 return GET_NATIVE_VIEW(env, obj)->key(PlatformKeyboardEvent(keyCode,
2868 unichar, repeatCount, isDown, isShift, isAlt, isSym));
2871 static void Click(JNIEnv *env, jobject obj, int framePtr, int nodePtr)
2873 #ifdef ANDROID_INSTRUMENT
2874 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
2876 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
2877 LOG_ASSERT(viewImpl, "viewImpl not set in Click");
2879 viewImpl->click(reinterpret_cast<WebCore::Frame*>(framePtr),
2880 reinterpret_cast<WebCore::Node*>(nodePtr));
2883 static void DeleteSelection(JNIEnv *env, jobject obj, jint start, jint end,
2884 jint textGeneration)
2886 #ifdef ANDROID_INSTRUMENT
2887 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
2889 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
2890 viewImpl->deleteSelection(start, end, textGeneration);
2893 static void SetSelection(JNIEnv *env, jobject obj, jint start, jint end)
2895 #ifdef ANDROID_INSTRUMENT
2896 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
2898 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
2899 viewImpl->setSelection(start, end);
2902 static jstring ModifySelection(JNIEnv *env, jobject obj, jstring alter, jstring direction, jstring granularity)
2904 #ifdef ANDROID_INSTRUMENT
2905 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
2907 String alterString = to_string(env, alter);
2908 String directionString = to_string(env, direction);
2909 String granularityString = to_string(env, granularity);
2911 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
2912 String selection_string = viewImpl->modifySelection(alterString,
2916 return WebCoreStringToJString(env, selection_string);
2919 static void ReplaceTextfieldText(JNIEnv *env, jobject obj,
2920 jint oldStart, jint oldEnd, jstring replace, jint start, jint end,
2921 jint textGeneration)
2923 #ifdef ANDROID_INSTRUMENT
2924 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
2926 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
2927 WebCore::String webcoreString = to_string(env, replace);
2928 viewImpl->replaceTextfieldText(oldStart,
2929 oldEnd, webcoreString, start, end, textGeneration);
2932 static void PassToJs(JNIEnv *env, jobject obj,
2933 jint generation, jstring currentText, jint keyCode,
2934 jint keyValue, jboolean down, jboolean cap, jboolean fn, jboolean sym)
2936 #ifdef ANDROID_INSTRUMENT
2937 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
2939 WebCore::String current = to_string(env, currentText);
2940 GET_NATIVE_VIEW(env, obj)->passToJs(generation, current,
2941 PlatformKeyboardEvent(keyCode, keyValue, 0, down, cap, fn, sym));
2944 static void ScrollFocusedTextInput(JNIEnv *env, jobject obj, jfloat xPercent,
2947 #ifdef ANDROID_INSTRUMENT
2948 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
2950 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
2951 viewImpl->scrollFocusedTextInput(xPercent, y);
2954 static void SetFocusControllerActive(JNIEnv *env, jobject obj, jboolean active)
2956 #ifdef ANDROID_INSTRUMENT
2957 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
2959 LOGV("webviewcore::nativeSetFocusControllerActive()\n");
2960 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
2961 LOG_ASSERT(viewImpl, "viewImpl not set in nativeSetFocusControllerActive");
2962 viewImpl->setFocusControllerActive(0, active);
2965 static void SaveDocumentState(JNIEnv *env, jobject obj, jint frame)
2967 #ifdef ANDROID_INSTRUMENT
2968 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
2970 LOGV("webviewcore::nativeSaveDocumentState()\n");
2971 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
2972 LOG_ASSERT(viewImpl, "viewImpl not set in nativeSaveDocumentState");
2973 viewImpl->saveDocumentState((WebCore::Frame*) frame);
2976 void WebViewCore::addVisitedLink(const UChar* string, int length)
2978 if (m_groupForVisitedLinks)
2979 m_groupForVisitedLinks->addVisitedLink(string, length);
2982 static jint RecordContent(JNIEnv *env, jobject obj, jobject region, jobject pt)
2984 #ifdef ANDROID_INSTRUMENT
2985 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
2987 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
2988 SkRegion* nativeRegion = GraphicsJNI::getNativeRegion(env, region);
2990 BaseLayerAndroid* result = viewImpl->recordContent(nativeRegion, &nativePt);
2991 GraphicsJNI::ipoint_to_jpoint(nativePt, env, pt);
2992 return reinterpret_cast<jint>(result);
2995 static void SplitContent(JNIEnv *env, jobject obj, jint content)
2997 #ifdef ANDROID_INSTRUMENT
2998 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
3000 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
3001 viewImpl->splitContent(reinterpret_cast<PictureSet*>(content));
3004 static void SendListBoxChoice(JNIEnv* env, jobject obj, jint choice)
3006 #ifdef ANDROID_INSTRUMENT
3007 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
3009 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
3010 LOG_ASSERT(viewImpl, "viewImpl not set in nativeSendListBoxChoice");
3011 viewImpl->popupReply(choice);
3014 // Set aside a predetermined amount of space in which to place the listbox
3015 // choices, to avoid unnecessary allocations.
3016 // The size here is arbitrary. We want the size to be at least as great as the
3017 // number of items in the average multiple-select listbox.
3018 #define PREPARED_LISTBOX_STORAGE 10
3020 static void SendListBoxChoices(JNIEnv* env, jobject obj, jbooleanArray jArray,
3023 #ifdef ANDROID_INSTRUMENT
3024 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
3026 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
3027 LOG_ASSERT(viewImpl, "viewImpl not set in nativeSendListBoxChoices");
3028 jboolean* ptrArray = env->GetBooleanArrayElements(jArray, 0);
3029 SkAutoSTMalloc<PREPARED_LISTBOX_STORAGE, int> storage(size);
3030 int* array = storage.get();
3032 for (int i = 0; i < size; i++) {
3037 env->ReleaseBooleanArrayElements(jArray, ptrArray, JNI_ABORT);
3038 viewImpl->popupReply(array, count);
3041 static jstring FindAddress(JNIEnv *env, jobject obj, jstring addr,
3042 jboolean caseInsensitive)
3044 #ifdef ANDROID_INSTRUMENT
3045 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
3049 int length = env->GetStringLength(addr);
3052 const jchar* addrChars = env->GetStringChars(addr, 0);
3054 bool success = CacheBuilder::FindAddress(addrChars, length,
3055 &start, &end, caseInsensitive) == CacheBuilder::FOUND_COMPLETE;
3058 ret = env->NewString((jchar*) addrChars + start, end - start);
3059 env->DeleteLocalRef(ret);
3061 env->ReleaseStringChars(addr, addrChars);
3065 static jboolean HandleTouchEvent(JNIEnv *env, jobject obj, jint action, jint x, jint y, jint metaState)
3067 #ifdef ANDROID_INSTRUMENT
3068 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
3070 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
3071 LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
3072 return viewImpl->handleTouchEvent(action, x, y, metaState);
3075 static void TouchUp(JNIEnv *env, jobject obj, jint touchGeneration,
3076 jint frame, jint node, jint x, jint y)
3078 #ifdef ANDROID_INSTRUMENT
3079 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
3081 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
3082 LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
3083 viewImpl->touchUp(touchGeneration,
3084 (WebCore::Frame*) frame, (WebCore::Node*) node, x, y);
3087 static jstring RetrieveHref(JNIEnv *env, jobject obj, jint frame,
3090 #ifdef ANDROID_INSTRUMENT
3091 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
3093 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
3094 LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
3095 WebCore::String result = viewImpl->retrieveHref((WebCore::Frame*) frame,
3096 (WebCore::Node*) node);
3097 if (!result.isEmpty())
3098 return WebCoreStringToJString(env, result);
3102 static jstring RetrieveAnchorText(JNIEnv *env, jobject obj, jint frame,
3105 #ifdef ANDROID_INSTRUMENT
3106 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
3108 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
3109 LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
3110 WebCore::String result = viewImpl->retrieveAnchorText((WebCore::Frame*) frame,
3111 (WebCore::Node*) node);
3112 if (!result.isEmpty())
3113 return WebCoreStringToJString(env, result);
3118 static void MoveFocus(JNIEnv *env, jobject obj, jint framePtr, jint nodePtr)
3120 #ifdef ANDROID_INSTRUMENT
3121 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
3123 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
3124 LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
3125 viewImpl->moveFocus((WebCore::Frame*) framePtr, (WebCore::Node*) nodePtr);
3128 static void MoveMouse(JNIEnv *env, jobject obj, jint frame,
3131 #ifdef ANDROID_INSTRUMENT
3132 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
3134 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
3135 LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
3136 viewImpl->moveMouse((WebCore::Frame*) frame, x, y);
3139 static void MoveMouseIfLatest(JNIEnv *env, jobject obj, jint moveGeneration,
3140 jint frame, jint x, jint y)
3142 #ifdef ANDROID_INSTRUMENT
3143 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
3145 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
3146 LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
3147 viewImpl->moveMouseIfLatest(moveGeneration,
3148 (WebCore::Frame*) frame, x, y);
3151 static void UpdateFrameCache(JNIEnv *env, jobject obj)
3153 #ifdef ANDROID_INSTRUMENT
3154 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
3156 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
3157 LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
3158 viewImpl->updateFrameCache();
3161 static jint GetContentMinPrefWidth(JNIEnv *env, jobject obj)
3163 #ifdef ANDROID_INSTRUMENT
3164 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
3166 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
3167 LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
3169 WebCore::Frame* frame = viewImpl->mainFrame();
3171 WebCore::Document* document = frame->document();
3173 WebCore::RenderObject* renderer = document->renderer();
3174 if (renderer && renderer->isRenderView()) {
3175 return renderer->minPrefWidth();
3182 static void SetViewportSettingsFromNative(JNIEnv *env, jobject obj)
3184 #ifdef ANDROID_INSTRUMENT
3185 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
3187 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
3188 LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
3190 WebCore::Settings* s = viewImpl->mainFrame()->page()->settings();
3194 #ifdef ANDROID_META_SUPPORT
3195 env->SetIntField(obj, gWebViewCoreFields.m_viewportWidth, s->viewportWidth());
3196 env->SetIntField(obj, gWebViewCoreFields.m_viewportHeight, s->viewportHeight());
3197 env->SetIntField(obj, gWebViewCoreFields.m_viewportInitialScale, s->viewportInitialScale());
3198 env->SetIntField(obj, gWebViewCoreFields.m_viewportMinimumScale, s->viewportMinimumScale());
3199 env->SetIntField(obj, gWebViewCoreFields.m_viewportMaximumScale, s->viewportMaximumScale());
3200 env->SetBooleanField(obj, gWebViewCoreFields.m_viewportUserScalable, s->viewportUserScalable());
3201 env->SetIntField(obj, gWebViewCoreFields.m_viewportDensityDpi, s->viewportTargetDensityDpi());
3205 static void SetBackgroundColor(JNIEnv *env, jobject obj, jint color)
3207 #ifdef ANDROID_INSTRUMENT
3208 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
3210 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
3211 LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
3213 viewImpl->setBackgroundColor((SkColor) color);
3216 static void DumpDomTree(JNIEnv *env, jobject obj, jboolean useFile)
3218 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
3219 LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
3221 viewImpl->dumpDomTree(useFile);
3224 static void DumpRenderTree(JNIEnv *env, jobject obj, jboolean useFile)
3226 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
3227 LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
3229 viewImpl->dumpRenderTree(useFile);
3232 static void DumpNavTree(JNIEnv *env, jobject obj)
3234 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
3235 LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
3237 viewImpl->dumpNavTree();
3240 static void DumpV8Counters(JNIEnv*, jobject)
3243 #ifdef ANDROID_INSTRUMENT
3244 V8Counters::dumpCounters();
3249 static void SetJsFlags(JNIEnv *env, jobject obj, jstring flags)
3252 WebCore::String flagsString = to_string(env, flags);
3253 WTF::CString utf8String = flagsString.utf8();
3254 WebCore::ScriptController::setFlags(utf8String.data(), utf8String.length());
3259 // Called from the Java side to set a new quota for the origin or new appcache
3260 // max size in response to a notification that the original quota was exceeded or
3261 // that the appcache has reached its maximum size.
3262 static void SetNewStorageLimit(JNIEnv* env, jobject obj, jlong quota) {
3263 #if ENABLE(DATABASE) || ENABLE(OFFLINE_WEB_APPLICATIONS)
3264 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
3265 Frame* frame = viewImpl->mainFrame();
3267 // The main thread is blocked awaiting this response, so now we can wake it
3269 ChromeClientAndroid* chromeC = static_cast<ChromeClientAndroid*>(frame->page()->chrome()->client());
3270 chromeC->wakeUpMainThreadWithNewQuota(quota);
3274 // Called from Java to provide a Geolocation permission state for the specified origin.
3275 static void GeolocationPermissionsProvide(JNIEnv* env, jobject obj, jstring origin, jboolean allow, jboolean remember) {
3276 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
3277 Frame* frame = viewImpl->mainFrame();
3279 ChromeClientAndroid* chromeClient = static_cast<ChromeClientAndroid*>(frame->page()->chrome()->client());
3280 chromeClient->provideGeolocationPermissions(to_string(env, origin), allow, remember);
3283 static void RegisterURLSchemeAsLocal(JNIEnv* env, jobject obj, jstring scheme) {
3284 #ifdef ANDROID_INSTRUMENT
3285 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
3287 WebCore::SecurityOrigin::registerURLSchemeAsLocal(to_string(env, scheme));
3290 static bool FocusBoundsChanged(JNIEnv* env, jobject obj)
3292 return GET_NATIVE_VIEW(env, obj)->focusBoundsChanged();
3295 static void Pause(JNIEnv* env, jobject obj)
3297 // This is called for the foreground tab when the browser is put to the
3298 // background (and also for any tab when it is put to the background of the
3299 // browser). The browser can only be killed by the system when it is in the
3300 // background, so saving the Geolocation permission state now ensures that
3301 // is maintained when the browser is killed.
3302 ChromeClient* chromeClient = GET_NATIVE_VIEW(env, obj)->mainFrame()->page()->chrome()->client();
3303 ChromeClientAndroid* chromeClientAndroid = static_cast<ChromeClientAndroid*>(chromeClient);
3304 chromeClientAndroid->storeGeolocationPermissions();
3306 Frame* mainFrame = GET_NATIVE_VIEW(env, obj)->mainFrame();
3307 for (Frame* frame = mainFrame; frame; frame = frame->tree()->traverseNext()) {
3308 Geolocation* geolocation = frame->domWindow()->navigator()->optionalGeolocation();
3310 geolocation->suspend();
3314 SkANP::InitEvent(&event, kLifecycle_ANPEventType);
3315 event.data.lifecycle.action = kPause_ANPLifecycleAction;
3316 GET_NATIVE_VIEW(env, obj)->sendPluginEvent(event);
3318 GET_NATIVE_VIEW(env, obj)->setIsPaused(true);
3321 static void Resume(JNIEnv* env, jobject obj)
3323 Frame* mainFrame = GET_NATIVE_VIEW(env, obj)->mainFrame();
3324 for (Frame* frame = mainFrame; frame; frame = frame->tree()->traverseNext()) {
3325 Geolocation* geolocation = frame->domWindow()->navigator()->optionalGeolocation();
3327 geolocation->resume();
3331 SkANP::InitEvent(&event, kLifecycle_ANPEventType);
3332 event.data.lifecycle.action = kResume_ANPLifecycleAction;
3333 GET_NATIVE_VIEW(env, obj)->sendPluginEvent(event);
3335 GET_NATIVE_VIEW(env, obj)->setIsPaused(false);
3338 static void FreeMemory(JNIEnv* env, jobject obj)
3341 SkANP::InitEvent(&event, kLifecycle_ANPEventType);
3342 event.data.lifecycle.action = kFreeMemory_ANPLifecycleAction;
3343 GET_NATIVE_VIEW(env, obj)->sendPluginEvent(event);
3346 static void ProvideVisitedHistory(JNIEnv *env, jobject obj, jobject hist)
3348 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
3349 LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
3351 jobjectArray array = static_cast<jobjectArray>(hist);
3353 jsize len = env->GetArrayLength(array);
3354 for (jsize i = 0; i < len; i++) {
3355 jstring item = static_cast<jstring>(env->GetObjectArrayElement(array, i));
3356 const UChar* str = static_cast<const UChar*>(env->GetStringChars(item, NULL));
3357 jsize len = env->GetStringLength(item);
3358 viewImpl->addVisitedLink(str, len);
3359 env->ReleaseStringChars(item, str);
3360 env->DeleteLocalRef(item);
3364 // Notification from the UI thread that the plugin's full-screen surface has been discarded
3365 static void FullScreenPluginHidden(JNIEnv* env, jobject obj, jint npp)
3367 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
3368 PluginWidgetAndroid* plugin = viewImpl->getPluginWidget((NPP)npp);
3370 plugin->exitFullScreen(false);
3373 static WebCore::IntRect jrect_to_webrect(JNIEnv* env, jobject obj)
3376 GraphicsJNI::get_jrect(env, obj, &L, &T, &R, &B);
3377 return WebCore::IntRect(L, T, R - L, B - T);
3380 static bool ValidNodeAndBounds(JNIEnv *env, jobject obj, int frame, int node,
3383 IntRect nativeRect = jrect_to_webrect(env, rect);
3384 return GET_NATIVE_VIEW(env, obj)->validNodeAndBounds(
3385 reinterpret_cast<Frame*>(frame),
3386 reinterpret_cast<Node*>(node), nativeRect);
3389 static jobject GetTouchHighlightRects(JNIEnv* env, jobject obj, jint x, jint y, jint slop)
3391 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
3394 Vector<IntRect> rects = viewImpl->getTouchHighlightRects(x, y, slop);
3395 if (rects.isEmpty())
3398 jclass arrayClass = env->FindClass("java/util/ArrayList");
3399 LOG_ASSERT(arrayClass, "Could not find java/util/ArrayList");
3400 jmethodID init = env->GetMethodID(arrayClass, "<init>", "(I)V");
3401 LOG_ASSERT(init, "Could not find constructor for ArrayList");
3402 jobject array = env->NewObject(arrayClass, init, rects.size());
3403 LOG_ASSERT(vector, "Could not create a new ArrayList");
3404 jmethodID add = env->GetMethodID(arrayClass, "add", "(Ljava/lang/Object;)Z");
3405 LOG_ASSERT(add, "Could not find add method on ArrayList");
3406 jclass rectClass = env->FindClass("android/graphics/Rect");
3407 LOG_ASSERT(rectClass, "Could not find android/graphics/Rect");
3408 jmethodID rectinit = env->GetMethodID(rectClass, "<init>", "(IIII)V");
3409 LOG_ASSERT(rectinit, "Could not find init method on Rect");
3411 for (size_t i = 0; i < rects.size(); i++) {
3412 jobject rect = env->NewObject(rectClass, rectinit, rects[i].x(),
3413 rects[i].y(), rects[i].right(), rects[i].bottom());
3415 env->CallBooleanMethod(array, add, rect);
3416 env->DeleteLocalRef(rect);
3420 env->DeleteLocalRef(rectClass);
3421 env->DeleteLocalRef(arrayClass);
3425 // ----------------------------------------------------------------------------
3430 static JNINativeMethod gJavaWebViewCoreMethods[] = {
3431 { "nativeFocusBoundsChanged", "()Z",
3432 (void*) FocusBoundsChanged } ,
3433 { "nativeKey", "(IIIZZZZ)Z",
3435 { "nativeClick", "(II)V",
3437 { "nativeSendListBoxChoices", "([ZI)V",
3438 (void*) SendListBoxChoices },
3439 { "nativeSendListBoxChoice", "(I)V",
3440 (void*) SendListBoxChoice },
3441 { "nativeSetSize", "(IIIFIIIIZ)V",
3443 { "nativeSetScrollOffset", "(III)V",
3444 (void*) SetScrollOffset },
3445 { "nativeSetGlobalBounds", "(IIII)V",
3446 (void*) SetGlobalBounds },
3447 { "nativeSetSelection", "(II)V",
3448 (void*) SetSelection } ,
3449 { "nativeModifySelection", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;",
3450 (void*) ModifySelection },
3451 { "nativeDeleteSelection", "(III)V",
3452 (void*) DeleteSelection } ,
3453 { "nativeReplaceTextfieldText", "(IILjava/lang/String;III)V",
3454 (void*) ReplaceTextfieldText } ,
3455 { "nativeMoveFocus", "(II)V",
3456 (void*) MoveFocus },
3457 { "nativeMoveMouse", "(III)V",
3458 (void*) MoveMouse },
3459 { "nativeMoveMouseIfLatest", "(IIII)V",
3460 (void*) MoveMouseIfLatest },
3461 { "passToJs", "(ILjava/lang/String;IIZZZZ)V",
3463 { "nativeScrollFocusedTextInput", "(FI)V",
3464 (void*) ScrollFocusedTextInput },
3465 { "nativeSetFocusControllerActive", "(Z)V",
3466 (void*) SetFocusControllerActive },
3467 { "nativeSaveDocumentState", "(I)V",
3468 (void*) SaveDocumentState },
3469 { "nativeFindAddress", "(Ljava/lang/String;Z)Ljava/lang/String;",
3470 (void*) FindAddress },
3471 { "nativeHandleTouchEvent", "(IIII)Z",
3472 (void*) HandleTouchEvent },
3473 { "nativeTouchUp", "(IIIII)V",
3475 { "nativeRetrieveHref", "(II)Ljava/lang/String;",
3476 (void*) RetrieveHref },
3477 { "nativeRetrieveAnchorText", "(II)Ljava/lang/String;",
3478 (void*) RetrieveAnchorText },
3479 { "nativeUpdateFrameCache", "()V",
3480 (void*) UpdateFrameCache },
3481 { "nativeGetContentMinPrefWidth", "()I",
3482 (void*) GetContentMinPrefWidth },
3483 { "nativeRecordContent", "(Landroid/graphics/Region;Landroid/graphics/Point;)I",
3484 (void*) RecordContent },
3485 { "setViewportSettingsFromNative", "()V",
3486 (void*) SetViewportSettingsFromNative },
3487 { "nativeSplitContent", "(I)V",
3488 (void*) SplitContent },
3489 { "nativeSetBackgroundColor", "(I)V",
3490 (void*) SetBackgroundColor },
3491 { "nativeRegisterURLSchemeAsLocal", "(Ljava/lang/String;)V",
3492 (void*) RegisterURLSchemeAsLocal },
3493 { "nativeDumpDomTree", "(Z)V",
3494 (void*) DumpDomTree },
3495 { "nativeDumpRenderTree", "(Z)V",
3496 (void*) DumpRenderTree },
3497 { "nativeDumpNavTree", "()V",
3498 (void*) DumpNavTree },
3499 { "nativeDumpV8Counters", "()V",
3500 (void*) DumpV8Counters },
3501 { "nativeSetNewStorageLimit", "(J)V",
3502 (void*) SetNewStorageLimit },
3503 { "nativeGeolocationPermissionsProvide", "(Ljava/lang/String;ZZ)V",
3504 (void*) GeolocationPermissionsProvide },
3505 { "nativePause", "()V", (void*) Pause },
3506 { "nativeResume", "()V", (void*) Resume },
3507 { "nativeFreeMemory", "()V", (void*) FreeMemory },
3508 { "nativeSetJsFlags", "(Ljava/lang/String;)V", (void*) SetJsFlags },
3509 { "nativeRequestLabel", "(II)Ljava/lang/String;",
3510 (void*) RequestLabel },
3511 { "nativeUpdateFrameCacheIfLoading", "()V",
3512 (void*) UpdateFrameCacheIfLoading },
3513 { "nativeProvideVisitedHistory", "([Ljava/lang/String;)V",
3514 (void*) ProvideVisitedHistory },
3515 { "nativeFullScreenPluginHidden", "(I)V",
3516 (void*) FullScreenPluginHidden },
3517 { "nativeValidNodeAndBounds", "(IILandroid/graphics/Rect;)Z",
3518 (void*) ValidNodeAndBounds },
3519 { "nativeGetTouchHighlightRects", "(III)Ljava/util/ArrayList;",
3520 (void*) GetTouchHighlightRects },
3523 int register_webviewcore(JNIEnv* env)
3525 jclass widget = env->FindClass("android/webkit/WebViewCore");
3527 "Unable to find class android/webkit/WebViewCore");
3528 gWebViewCoreFields.m_nativeClass = env->GetFieldID(widget, "mNativeClass",
3530 LOG_ASSERT(gWebViewCoreFields.m_nativeClass,
3531 "Unable to find android/webkit/WebViewCore.mNativeClass");
3532 gWebViewCoreFields.m_viewportWidth = env->GetFieldID(widget,
3533 "mViewportWidth", "I");
3534 LOG_ASSERT(gWebViewCoreFields.m_viewportWidth,
3535 "Unable to find android/webkit/WebViewCore.mViewportWidth");
3536 gWebViewCoreFields.m_viewportHeight = env->GetFieldID(widget,
3537 "mViewportHeight", "I");
3538 LOG_ASSERT(gWebViewCoreFields.m_viewportHeight,
3539 "Unable to find android/webkit/WebViewCore.mViewportHeight");
3540 gWebViewCoreFields.m_viewportInitialScale = env->GetFieldID(widget,
3541 "mViewportInitialScale", "I");
3542 LOG_ASSERT(gWebViewCoreFields.m_viewportInitialScale,
3543 "Unable to find android/webkit/WebViewCore.mViewportInitialScale");
3544 gWebViewCoreFields.m_viewportMinimumScale = env->GetFieldID(widget,
3545 "mViewportMinimumScale", "I");
3546 LOG_ASSERT(gWebViewCoreFields.m_viewportMinimumScale,
3547 "Unable to find android/webkit/WebViewCore.mViewportMinimumScale");
3548 gWebViewCoreFields.m_viewportMaximumScale = env->GetFieldID(widget,
3549 "mViewportMaximumScale", "I");
3550 LOG_ASSERT(gWebViewCoreFields.m_viewportMaximumScale,
3551 "Unable to find android/webkit/WebViewCore.mViewportMaximumScale");
3552 gWebViewCoreFields.m_viewportUserScalable = env->GetFieldID(widget,
3553 "mViewportUserScalable", "Z");
3554 LOG_ASSERT(gWebViewCoreFields.m_viewportUserScalable,
3555 "Unable to find android/webkit/WebViewCore.mViewportUserScalable");
3556 gWebViewCoreFields.m_viewportDensityDpi = env->GetFieldID(widget,
3557 "mViewportDensityDpi", "I");
3558 LOG_ASSERT(gWebViewCoreFields.m_viewportDensityDpi,
3559 "Unable to find android/webkit/WebViewCore.mViewportDensityDpi");
3560 gWebViewCoreFields.m_webView = env->GetFieldID(widget,
3561 "mWebView", "Landroid/webkit/WebView;");
3562 LOG_ASSERT(gWebViewCoreFields.m_webView,
3563 "Unable to find android/webkit/WebViewCore.mWebView");
3565 return jniRegisterNativeMethods(env, "android/webkit/WebViewCore",
3566 gJavaWebViewCoreMethods, NELEM(gJavaWebViewCoreMethods));
3569 } /* namespace android */