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 "AccessibilityObject.h"
32 #include "Attribute.h"
33 #include "BaseLayerAndroid.h"
34 #include "CachedNode.h"
35 #include "CachedRoot.h"
37 #include "ChromeClientAndroid.h"
38 #include "ChromiumIncludes.h"
39 #include "ClientRect.h"
40 #include "ClientRectList.h"
42 #include "CSSPropertyNames.h"
43 #include "CSSValueKeywords.h"
44 #include "DatabaseTracker.h"
46 #include "DOMWindow.h"
47 #include "DOMSelection.h"
50 #include "EditorClientAndroid.h"
51 #include "EventHandler.h"
52 #include "EventNames.h"
53 #include "ExceptionCode.h"
54 #include "FocusController.h"
57 #include "FrameLoader.h"
58 #include "FrameLoaderClientAndroid.h"
59 #include "FrameTree.h"
60 #include "FrameView.h"
61 #include "Geolocation.h"
62 #include "GraphicsContext.h"
63 #include "GraphicsJNI.h"
64 #include "HTMLAnchorElement.h"
65 #include "HTMLAreaElement.h"
66 #include "HTMLElement.h"
67 #include "HTMLFormControlElement.h"
68 #include "HTMLImageElement.h"
69 #include "HTMLInputElement.h"
70 #include "HTMLLabelElement.h"
71 #include "HTMLMapElement.h"
72 #include "HTMLNames.h"
73 #include "HTMLOptGroupElement.h"
74 #include "HTMLOptionElement.h"
75 #include "HTMLSelectElement.h"
76 #include "HTMLTextAreaElement.h"
77 #include "HistoryItem.h"
78 #include "HitTestRequest.h"
79 #include "HitTestResult.h"
80 #include "InlineTextBox.h"
81 #include "MemoryUsage.h"
82 #include "NamedNodeMap.h"
83 #include "Navigator.h"
87 #include "PageGroup.h"
88 #include "PlatformKeyboardEvent.h"
89 #include "PlatformString.h"
90 #include "PluginWidgetAndroid.h"
91 #include "PluginView.h"
93 #include "ProgressTracker.h"
95 #include "RenderBox.h"
96 #include "RenderInline.h"
97 #include "RenderLayer.h"
98 #include "RenderPart.h"
99 #include "RenderText.h"
100 #include "RenderTextControl.h"
101 #include "RenderThemeAndroid.h"
102 #include "RenderView.h"
103 #include "ResourceRequest.h"
104 #include "SchemeRegistry.h"
105 #include "SelectionController.h"
106 #include "Settings.h"
108 #include "SkTemplates.h"
109 #include "SkTDArray.h"
111 #include "SkCanvas.h"
112 #include "SkPicture.h"
115 #include "TypingCommand.h"
116 #include "WebCoreFrameBridge.h"
117 #include "WebFrameView.h"
118 #include "WindowsKeyboardCodes.h"
119 #include "android_graphics.h"
120 #include "autofill/WebAutoFill.h"
121 #include "htmlediting.h"
125 #include <JNIUtility.h>
126 #include <ui/KeycodeLabels.h>
127 #include <wtf/CurrentTime.h>
128 #include <wtf/text/AtomicString.h>
129 #include <wtf/text/StringImpl.h>
132 #include "ScriptController.h"
133 #include "V8Counters.h"
134 #include <wtf/text/CString.h>
141 #if ENABLE(TOUCH_EVENTS) // Android
142 #include "PlatformTouchEvent.h"
145 #ifdef ANDROID_DOM_LOGGING
146 #include "AndroidLog.h"
147 #include "RenderTreeAsText.h"
148 #include <wtf/text/CString.h>
150 FILE* gDomTreeFile = 0;
151 FILE* gRenderTreeFile = 0;
154 #ifdef ANDROID_INSTRUMENT
155 #include "TimeCounter.h"
158 #if USE(ACCELERATED_COMPOSITING)
159 #include "GraphicsLayerAndroid.h"
160 #include "RenderLayerCompositor.h"
163 /* We pass this flag when recording the actual content, so that we don't spend
164 time actually regionizing complex path clips, when all we really want to do
167 #define PICT_RECORD_FLAGS SkPicture::kUsePathBoundsForClip_RecordingFlag
169 ////////////////////////////////////////////////////////////////////////////////////////////////
173 static SkTDArray<WebViewCore*> gInstanceList;
175 void WebViewCore::addInstance(WebViewCore* inst) {
176 *gInstanceList.append() = inst;
179 void WebViewCore::removeInstance(WebViewCore* inst) {
180 int index = gInstanceList.find(inst);
181 LOG_ASSERT(index >= 0, "RemoveInstance inst not found");
183 gInstanceList.removeShuffle(index);
187 bool WebViewCore::isInstance(WebViewCore* inst) {
188 return gInstanceList.find(inst) >= 0;
191 jobject WebViewCore::getApplicationContext() {
193 // check to see if there is a valid webviewcore object
194 if (gInstanceList.isEmpty())
197 // get the context from the webview
198 jobject context = gInstanceList[0]->getContext();
203 // get the application context using JNI
204 JNIEnv* env = JSC::Bindings::getJNIEnv();
205 jclass contextClass = env->GetObjectClass(context);
206 jmethodID appContextMethod = env->GetMethodID(contextClass, "getApplicationContext", "()Landroid/content/Context;");
207 env->DeleteLocalRef(contextClass);
208 jobject result = env->CallObjectMethod(context, appContextMethod);
214 struct WebViewCoreStaticMethods {
215 jmethodID m_isSupportedMediaMimeType;
216 } gWebViewCoreStaticMethods;
218 // Check whether a media mimeType is supported in Android media framework.
219 bool WebViewCore::isSupportedMediaMimeType(const WTF::String& mimeType) {
220 JNIEnv* env = JSC::Bindings::getJNIEnv();
221 jstring jMimeType = wtfStringToJstring(env, mimeType);
222 jclass webViewCore = env->FindClass("android/webkit/WebViewCore");
223 bool val = env->CallStaticBooleanMethod(webViewCore,
224 gWebViewCoreStaticMethods.m_isSupportedMediaMimeType, jMimeType);
226 env->DeleteLocalRef(webViewCore);
227 env->DeleteLocalRef(jMimeType);
232 // ----------------------------------------------------------------------------
234 #define GET_NATIVE_VIEW(env, obj) ((WebViewCore*)env->GetIntField(obj, gWebViewCoreFields.m_nativeClass))
236 // Field ids for WebViewCore
237 struct WebViewCoreFields {
238 jfieldID m_nativeClass;
239 jfieldID m_viewportWidth;
240 jfieldID m_viewportHeight;
241 jfieldID m_viewportInitialScale;
242 jfieldID m_viewportMinimumScale;
243 jfieldID m_viewportMaximumScale;
244 jfieldID m_viewportUserScalable;
245 jfieldID m_viewportDensityDpi;
247 jfieldID m_drawIsPaused;
248 jfieldID m_lowMemoryUsageMb;
249 jfieldID m_highMemoryUsageMb;
250 jfieldID m_highUsageDeltaMb;
251 } gWebViewCoreFields;
253 // ----------------------------------------------------------------------------
255 struct WebViewCore::JavaGlue {
257 jmethodID m_scrollTo;
258 jmethodID m_contentDraw;
259 jmethodID m_layersDraw;
260 jmethodID m_requestListBox;
261 jmethodID m_openFileChooser;
262 jmethodID m_requestSingleListBox;
264 jmethodID m_jsConfirm;
265 jmethodID m_jsPrompt;
266 jmethodID m_jsUnload;
267 jmethodID m_jsInterrupt;
268 jmethodID m_didFirstLayout;
269 jmethodID m_updateViewport;
270 jmethodID m_sendNotifyProgressFinished;
271 jmethodID m_sendViewInvalidate;
272 jmethodID m_updateTextfield;
273 jmethodID m_updateTextSelection;
274 jmethodID m_clearTextEntry;
275 jmethodID m_restoreScale;
276 jmethodID m_needTouchEvents;
277 jmethodID m_requestKeyboard;
278 jmethodID m_requestKeyboardWithSelection;
279 jmethodID m_exceededDatabaseQuota;
280 jmethodID m_reachedMaxAppCacheSize;
281 jmethodID m_populateVisitedLinks;
282 jmethodID m_geolocationPermissionsShowPrompt;
283 jmethodID m_geolocationPermissionsHidePrompt;
284 jmethodID m_getDeviceMotionService;
285 jmethodID m_getDeviceOrientationService;
286 jmethodID m_addMessageToConsole;
287 jmethodID m_formDidBlur;
288 jmethodID m_getPluginClass;
289 jmethodID m_showFullScreenPlugin;
290 jmethodID m_hideFullScreenPlugin;
291 jmethodID m_createSurface;
292 jmethodID m_addSurface;
293 jmethodID m_updateSurface;
294 jmethodID m_destroySurface;
295 jmethodID m_getContext;
296 jmethodID m_keepScreenOn;
297 jmethodID m_sendFindAgain;
298 jmethodID m_showRect;
299 jmethodID m_centerFitRect;
300 jmethodID m_setScrollbarModes;
301 jmethodID m_setInstallableWebApp;
302 jmethodID m_enterFullscreenForVideoLayer;
303 jmethodID m_setWebTextViewAutoFillable;
304 jmethodID m_selectAt;
305 AutoJObject object(JNIEnv* env) {
306 return getRealObject(env, m_obj);
311 * WebViewCore Implementation
314 static jmethodID GetJMethod(JNIEnv* env, jclass clazz, const char name[], const char signature[])
316 jmethodID m = env->GetMethodID(clazz, name, signature);
317 LOG_ASSERT(m, "Could not find method %s", name);
321 Mutex WebViewCore::gFrameCacheMutex;
322 Mutex WebViewCore::gButtonMutex;
323 Mutex WebViewCore::gCursorBoundsMutex;
325 WebViewCore::WebViewCore(JNIEnv* env, jobject javaWebViewCore, WebCore::Frame* mainframe)
326 : m_pluginInvalTimer(this, &WebViewCore::pluginInvalTimerFired)
327 , m_deviceMotionAndOrientationManager(this)
329 m_mainFrame = mainframe;
332 m_moveGeneration = 0;
333 m_lastGeneration = 0;
334 m_touchGeneration = 0;
335 m_blockTextfieldUpdates = false;
336 // just initial values. These should be set by client
337 m_maxXScroll = 320/4;
338 m_maxYScroll = 240/4;
339 m_textGeneration = 0;
341 m_textWrapWidth = 320;
343 #if ENABLE(TOUCH_EVENTS)
344 m_forwardingTouchEvents = false;
347 m_screenOnCounter = 0;
348 m_shouldPaintCaret = true;
350 LOG_ASSERT(m_mainFrame, "Uh oh, somehow a frameview was made without an initial frame!");
352 jclass clazz = env->GetObjectClass(javaWebViewCore);
353 m_javaGlue = new JavaGlue;
354 m_javaGlue->m_obj = env->NewWeakGlobalRef(javaWebViewCore);
355 m_javaGlue->m_scrollTo = GetJMethod(env, clazz, "contentScrollTo", "(IIZZ)V");
356 m_javaGlue->m_contentDraw = GetJMethod(env, clazz, "contentDraw", "()V");
357 m_javaGlue->m_layersDraw = GetJMethod(env, clazz, "layersDraw", "()V");
358 m_javaGlue->m_requestListBox = GetJMethod(env, clazz, "requestListBox", "([Ljava/lang/String;[I[I)V");
359 m_javaGlue->m_openFileChooser = GetJMethod(env, clazz, "openFileChooser", "(Ljava/lang/String;)Ljava/lang/String;");
360 m_javaGlue->m_requestSingleListBox = GetJMethod(env, clazz, "requestListBox", "([Ljava/lang/String;[II)V");
361 m_javaGlue->m_jsAlert = GetJMethod(env, clazz, "jsAlert", "(Ljava/lang/String;Ljava/lang/String;)V");
362 m_javaGlue->m_jsConfirm = GetJMethod(env, clazz, "jsConfirm", "(Ljava/lang/String;Ljava/lang/String;)Z");
363 m_javaGlue->m_jsPrompt = GetJMethod(env, clazz, "jsPrompt", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;");
364 m_javaGlue->m_jsUnload = GetJMethod(env, clazz, "jsUnload", "(Ljava/lang/String;Ljava/lang/String;)Z");
365 m_javaGlue->m_jsInterrupt = GetJMethod(env, clazz, "jsInterrupt", "()Z");
366 m_javaGlue->m_didFirstLayout = GetJMethod(env, clazz, "didFirstLayout", "(Z)V");
367 m_javaGlue->m_updateViewport = GetJMethod(env, clazz, "updateViewport", "()V");
368 m_javaGlue->m_sendNotifyProgressFinished = GetJMethod(env, clazz, "sendNotifyProgressFinished", "()V");
369 m_javaGlue->m_sendViewInvalidate = GetJMethod(env, clazz, "sendViewInvalidate", "(IIII)V");
370 m_javaGlue->m_updateTextfield = GetJMethod(env, clazz, "updateTextfield", "(IZLjava/lang/String;I)V");
371 m_javaGlue->m_updateTextSelection = GetJMethod(env, clazz, "updateTextSelection", "(IIII)V");
372 m_javaGlue->m_clearTextEntry = GetJMethod(env, clazz, "clearTextEntry", "()V");
373 m_javaGlue->m_restoreScale = GetJMethod(env, clazz, "restoreScale", "(FF)V");
374 m_javaGlue->m_needTouchEvents = GetJMethod(env, clazz, "needTouchEvents", "(Z)V");
375 m_javaGlue->m_requestKeyboard = GetJMethod(env, clazz, "requestKeyboard", "(Z)V");
376 m_javaGlue->m_requestKeyboardWithSelection = GetJMethod(env, clazz, "requestKeyboardWithSelection", "(IIII)V");
377 m_javaGlue->m_exceededDatabaseQuota = GetJMethod(env, clazz, "exceededDatabaseQuota", "(Ljava/lang/String;Ljava/lang/String;JJ)V");
378 m_javaGlue->m_reachedMaxAppCacheSize = GetJMethod(env, clazz, "reachedMaxAppCacheSize", "(J)V");
379 m_javaGlue->m_populateVisitedLinks = GetJMethod(env, clazz, "populateVisitedLinks", "()V");
380 m_javaGlue->m_geolocationPermissionsShowPrompt = GetJMethod(env, clazz, "geolocationPermissionsShowPrompt", "(Ljava/lang/String;)V");
381 m_javaGlue->m_geolocationPermissionsHidePrompt = GetJMethod(env, clazz, "geolocationPermissionsHidePrompt", "()V");
382 m_javaGlue->m_getDeviceMotionService = GetJMethod(env, clazz, "getDeviceMotionService", "()Landroid/webkit/DeviceMotionService;");
383 m_javaGlue->m_getDeviceOrientationService = GetJMethod(env, clazz, "getDeviceOrientationService", "()Landroid/webkit/DeviceOrientationService;");
384 m_javaGlue->m_addMessageToConsole = GetJMethod(env, clazz, "addMessageToConsole", "(Ljava/lang/String;ILjava/lang/String;I)V");
385 m_javaGlue->m_formDidBlur = GetJMethod(env, clazz, "formDidBlur", "(I)V");
386 m_javaGlue->m_getPluginClass = GetJMethod(env, clazz, "getPluginClass", "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/Class;");
387 m_javaGlue->m_showFullScreenPlugin = GetJMethod(env, clazz, "showFullScreenPlugin", "(Landroid/webkit/ViewManager$ChildView;I)V");
388 m_javaGlue->m_hideFullScreenPlugin = GetJMethod(env, clazz, "hideFullScreenPlugin", "()V");
389 m_javaGlue->m_createSurface = GetJMethod(env, clazz, "createSurface", "(Landroid/view/View;)Landroid/webkit/ViewManager$ChildView;");
390 m_javaGlue->m_addSurface = GetJMethod(env, clazz, "addSurface", "(Landroid/view/View;IIII)Landroid/webkit/ViewManager$ChildView;");
391 m_javaGlue->m_updateSurface = GetJMethod(env, clazz, "updateSurface", "(Landroid/webkit/ViewManager$ChildView;IIII)V");
392 m_javaGlue->m_destroySurface = GetJMethod(env, clazz, "destroySurface", "(Landroid/webkit/ViewManager$ChildView;)V");
393 m_javaGlue->m_getContext = GetJMethod(env, clazz, "getContext", "()Landroid/content/Context;");
394 m_javaGlue->m_keepScreenOn = GetJMethod(env, clazz, "keepScreenOn", "(Z)V");
395 m_javaGlue->m_sendFindAgain = GetJMethod(env, clazz, "sendFindAgain", "()V");
396 m_javaGlue->m_showRect = GetJMethod(env, clazz, "showRect", "(IIIIIIFFFF)V");
397 m_javaGlue->m_centerFitRect = GetJMethod(env, clazz, "centerFitRect", "(IIII)V");
398 m_javaGlue->m_setScrollbarModes = GetJMethod(env, clazz, "setScrollbarModes", "(II)V");
399 m_javaGlue->m_setInstallableWebApp = GetJMethod(env, clazz, "setInstallableWebApp", "()V");
401 m_javaGlue->m_enterFullscreenForVideoLayer = GetJMethod(env, clazz, "enterFullscreenForVideoLayer", "(ILjava/lang/String;)V");
403 m_javaGlue->m_setWebTextViewAutoFillable = GetJMethod(env, clazz, "setWebTextViewAutoFillable", "(ILjava/lang/String;)V");
404 m_javaGlue->m_selectAt = GetJMethod(env, clazz, "selectAt", "(II)V");
405 env->DeleteLocalRef(clazz);
407 env->SetIntField(javaWebViewCore, gWebViewCoreFields.m_nativeClass, (jint)this);
409 m_scrollOffsetX = m_scrollOffsetY = 0;
411 PageGroup::setShouldTrackVisitedLinks(true);
415 MemoryUsage::setLowMemoryUsageMb(env->GetIntField(javaWebViewCore, gWebViewCoreFields.m_lowMemoryUsageMb));
416 MemoryUsage::setHighMemoryUsageMb(env->GetIntField(javaWebViewCore, gWebViewCoreFields.m_highMemoryUsageMb));
417 MemoryUsage::setHighUsageDeltaMb(env->GetIntField(javaWebViewCore, gWebViewCoreFields.m_highUsageDeltaMb));
419 WebViewCore::addInstance(this);
421 #if USE(CHROME_NETWORK_STACK)
422 AndroidNetworkLibraryImpl::InitWithApplicationContext(env, 0);
426 WebViewCore::~WebViewCore()
428 WebViewCore::removeInstance(this);
430 // Release the focused view
431 Release(m_popupReply);
433 if (m_javaGlue->m_obj) {
434 JNIEnv* env = JSC::Bindings::getJNIEnv();
435 env->DeleteWeakGlobalRef(m_javaGlue->m_obj);
436 m_javaGlue->m_obj = 0;
439 delete m_frameCacheKit;
440 delete m_navPictureKit;
443 WebViewCore* WebViewCore::getWebViewCore(const WebCore::FrameView* view)
445 return getWebViewCore(static_cast<const WebCore::ScrollView*>(view));
448 WebViewCore* WebViewCore::getWebViewCore(const WebCore::ScrollView* view)
453 WebFrameView* webFrameView = static_cast<WebFrameView*>(view->platformWidget());
456 return webFrameView->webViewCore();
459 void WebViewCore::reset(bool fromConstructor)
462 if (fromConstructor) {
466 gFrameCacheMutex.lock();
467 delete m_frameCacheKit;
468 delete m_navPictureKit;
471 gFrameCacheMutex.unlock();
475 m_blurringNodePointer = 0;
476 m_lastFocusedBounds = WebCore::IntRect(0,0,0,0);
477 m_focusBoundsChanged = false;
478 m_lastFocusedSelStart = 0;
479 m_lastFocusedSelEnd = 0;
481 m_updatedFrameCache = true;
482 m_frameCacheOutOfDate = true;
483 m_skipContentDraw = false;
485 m_domtree_version = 0;
486 m_check_domtree_version = true;
487 m_progressDone = false;
488 m_hasCursorBounds = false;
494 m_groupForVisitedLinks = 0;
495 m_currentNodeDomNavigationAxis = 0;
498 static bool layoutIfNeededRecursive(WebCore::Frame* f)
503 WebCore::FrameView* v = f->view();
507 if (v->needsLayout())
508 v->layout(f->tree()->parent());
510 WebCore::Frame* child = f->tree()->firstChild();
513 success &= layoutIfNeededRecursive(child);
514 child = child->tree()->nextSibling();
517 return success && !v->needsLayout();
520 CacheBuilder& WebViewCore::cacheBuilder()
522 return FrameLoaderClientAndroid::get(m_mainFrame)->getCacheBuilder();
525 WebCore::Node* WebViewCore::currentFocus()
527 return cacheBuilder().currentFocus();
530 void WebViewCore::recordPicture(SkPicture* picture)
532 // if there is no document yet, just return
533 if (!m_mainFrame->document()) {
534 DBG_NAV_LOG("no document");
537 // Call layout to ensure that the contentWidth and contentHeight are correct
538 if (!layoutIfNeededRecursive(m_mainFrame)) {
539 DBG_NAV_LOG("layout failed");
542 // draw into the picture's recording canvas
543 WebCore::FrameView* view = m_mainFrame->view();
544 DBG_NAV_LOGD("view=(w=%d,h=%d)", view->contentsWidth(),
545 view->contentsHeight());
546 SkAutoPictureRecord arp(picture, view->contentsWidth(),
547 view->contentsHeight(), PICT_RECORD_FLAGS);
548 SkAutoMemoryUsageProbe mup(__FUNCTION__);
550 // Copy m_buttons so we can pass it to our graphics context.
552 WTF::Vector<Container> buttons(m_buttons);
553 gButtonMutex.unlock();
555 WebCore::PlatformGraphicsContext pgc(arp.getRecordingCanvas(), &buttons);
556 WebCore::GraphicsContext gc(&pgc);
557 view->platformWidget()->draw(&gc, WebCore::IntRect(0, 0,
558 view->contentsWidth(), view->contentsHeight()));
561 updateButtonList(&buttons);
562 gButtonMutex.unlock();
565 void WebViewCore::recordPictureSet(PictureSet* content)
567 // if there is no document yet, just return
568 if (!m_mainFrame->document()) {
569 DBG_SET_LOG("!m_mainFrame->document()");
572 if (m_addInval.isEmpty()) {
573 DBG_SET_LOG("m_addInval.isEmpty()");
576 // Call layout to ensure that the contentWidth and contentHeight are correct
577 // it's fine for layout to gather invalidates, but defeat sending a message
578 // back to java to call webkitDraw, since we're already in the middle of
580 m_skipContentDraw = true;
581 bool success = layoutIfNeededRecursive(m_mainFrame);
582 m_skipContentDraw = false;
584 // We may be mid-layout and thus cannot draw.
588 { // collect WebViewCoreRecordTimeCounter after layoutIfNeededRecursive
589 #ifdef ANDROID_INSTRUMENT
590 TimeCounterAuto counter(TimeCounter::WebViewCoreRecordTimeCounter);
593 // if the webkit page dimensions changed, discard the pictureset and redraw.
594 WebCore::FrameView* view = m_mainFrame->view();
595 int width = view->contentsWidth();
596 int height = view->contentsHeight();
598 // Use the contents width and height as a starting point.
600 contentRect.set(0, 0, width, height);
601 SkIRect total(contentRect);
603 // Traverse all the frames and add their sizes if they are in the visible
605 for (WebCore::Frame* frame = m_mainFrame->tree()->traverseNext(); frame;
606 frame = frame->tree()->traverseNext()) {
607 // If the frame doesn't have an owner then it is the top frame and the
608 // view size is the frame size.
609 WebCore::RenderPart* owner = frame->ownerRenderer();
610 if (owner && owner->style()->visibility() == VISIBLE) {
614 // Traverse the tree up to the parent to find the absolute position
616 WebCore::Frame* parent = frame->tree()->parent();
618 WebCore::RenderPart* parentOwner = parent->ownerRenderer();
620 x += parentOwner->x();
621 y += parentOwner->y();
623 parent = parent->tree()->parent();
625 // Use the owner dimensions so that padding and border are
627 int right = x + owner->width();
628 int bottom = y + owner->height();
629 SkIRect frameRect = {x, y, right, bottom};
630 // Ignore a width or height that is smaller than 1. Some iframes
631 // have small dimensions in order to be hidden. The iframe
632 // expansion code does not expand in that case so we should ignore
634 if (frameRect.width() > 1 && frameRect.height() > 1
635 && SkIRect::Intersects(total, frameRect))
636 total.join(x, y, right, bottom);
640 // If the new total is larger than the content, resize the view to include
642 if (!contentRect.contains(total)) {
643 // Resize the view to change the overflow clip.
644 view->resize(total.fRight, total.fBottom);
646 // We have to force a layout in order for the clip to change.
647 m_mainFrame->contentRenderer()->setNeedsLayoutAndPrefWidthsRecalc();
650 // Relayout similar to above
651 m_skipContentDraw = true;
652 bool success = layoutIfNeededRecursive(m_mainFrame);
653 m_skipContentDraw = false;
657 // Set the computed content width
658 width = view->contentsWidth();
659 height = view->contentsHeight();
662 if (cacheBuilder().pictureSetDisabled())
665 content->checkDimensions(width, height, &m_addInval);
667 // The inval region may replace existing pictures. The existing pictures
668 // may have already been split into pieces. If reuseSubdivided() returns
669 // true, the split pieces are the last entries in the picture already. They
670 // are marked as invalid, and are rebuilt by rebuildPictureSet().
672 // If the new region doesn't match a set of split pieces, add it to the end.
673 if (!content->reuseSubdivided(m_addInval)) {
674 const SkIRect& inval = m_addInval.getBounds();
675 SkPicture* picture = rebuildPicture(inval);
676 DBG_SET_LOGD("{%d,%d,w=%d,h=%d}", inval.fLeft,
677 inval.fTop, inval.width(), inval.height());
678 content->add(m_addInval, picture, 0, false);
679 SkSafeUnref(picture);
681 // Remove any pictures already in the set that are obscured by the new one,
682 // and check to see if any already split pieces need to be redrawn.
683 if (content->build())
684 rebuildPictureSet(content);
685 } // WebViewCoreRecordTimeCounter
686 WebCore::Node* oldFocusNode = currentFocus();
687 m_frameCacheOutOfDate = true;
688 WebCore::IntRect oldBounds;
692 oldBounds = oldFocusNode->getRect();
693 RenderObject* renderer = oldFocusNode->renderer();
694 if (renderer && (renderer->isTextArea() || renderer->isTextField())) {
695 WebCore::RenderTextControl* rtc =
696 static_cast<WebCore::RenderTextControl*>(renderer);
697 oldSelStart = rtc->selectionStart();
698 oldSelEnd = rtc->selectionEnd();
701 oldBounds = WebCore::IntRect(0,0,0,0);
702 unsigned latestVersion = 0;
703 if (m_check_domtree_version) {
704 // as domTreeVersion only increment, we can just check the sum to see
705 // whether we need to update the frame cache
706 for (Frame* frame = m_mainFrame; frame; frame = frame->tree()->traverseNext()) {
707 const Document* doc = frame->document();
708 latestVersion += doc->domTreeVersion() + doc->styleVersion();
711 DBG_NAV_LOGD("m_lastFocused=%p oldFocusNode=%p"
712 " m_lastFocusedBounds={%d,%d,%d,%d} oldBounds={%d,%d,%d,%d}"
713 " m_lastFocusedSelection={%d,%d} oldSelection={%d,%d}"
714 " m_check_domtree_version=%s latestVersion=%d m_domtree_version=%d",
715 m_lastFocused, oldFocusNode,
716 m_lastFocusedBounds.x(), m_lastFocusedBounds.y(),
717 m_lastFocusedBounds.width(), m_lastFocusedBounds.height(),
718 oldBounds.x(), oldBounds.y(), oldBounds.width(), oldBounds.height(),
719 m_lastFocusedSelStart, m_lastFocusedSelEnd, oldSelStart, oldSelEnd,
720 m_check_domtree_version ? "true" : "false",
721 latestVersion, m_domtree_version);
722 if (m_lastFocused == oldFocusNode && m_lastFocusedBounds == oldBounds
723 && m_lastFocusedSelStart == oldSelStart
724 && m_lastFocusedSelEnd == oldSelEnd
726 && (!m_check_domtree_version || latestVersion == m_domtree_version))
730 m_focusBoundsChanged |= m_lastFocused == oldFocusNode
731 && m_lastFocusedBounds != oldBounds;
732 m_lastFocused = oldFocusNode;
733 m_lastFocusedBounds = oldBounds;
734 m_lastFocusedSelStart = oldSelStart;
735 m_lastFocusedSelEnd = oldSelEnd;
736 m_domtree_version = latestVersion;
737 DBG_NAV_LOG("call updateFrameCache");
740 LOG_ASSERT(m_javaGlue->m_obj,
741 "A Java widget was not associated with this view bridge!");
742 JNIEnv* env = JSC::Bindings::getJNIEnv();
743 env->CallVoidMethod(m_javaGlue->object(env).get(),
744 m_javaGlue->m_sendFindAgain);
749 void WebViewCore::updateButtonList(WTF::Vector<Container>* buttons)
751 // All the entries in buttons are either updates of previous entries in
752 // m_buttons or they need to be added to it.
753 Container* end = buttons->end();
754 for (Container* updatedContainer = buttons->begin();
755 updatedContainer != end; updatedContainer++) {
756 bool updated = false;
757 // Search for a previous entry that references the same node as our new
759 Container* lastPossibleMatch = m_buttons.end();
760 for (Container* possibleMatch = m_buttons.begin();
761 possibleMatch != lastPossibleMatch; possibleMatch++) {
762 if (updatedContainer->matches(possibleMatch->node())) {
763 // Update our record, and skip to the next one.
764 possibleMatch->setRect(updatedContainer->rect());
770 // This is a brand new button, so append it to m_buttons
771 m_buttons.append(*updatedContainer);
775 // count will decrease each time one is removed, so check count each time.
776 while (i < m_buttons.size()) {
777 if (m_buttons[i].canBeRemoved()) {
778 m_buttons[i] = m_buttons.last();
779 m_buttons.removeLast();
786 // note: updateCursorBounds is called directly by the WebView thread
787 // This needs to be called each time we call CachedRoot::setCursor() with
788 // non-null CachedNode/CachedFrame, since otherwise the WebViewCore's data
789 // about the cursor is incorrect. When we call setCursor(0,0), we need
790 // to set hasCursorBounds to false.
791 void WebViewCore::updateCursorBounds(const CachedRoot* root,
792 const CachedFrame* cachedFrame, const CachedNode* cachedNode)
794 LOG_ASSERT(root, "updateCursorBounds: root cannot be null");
795 LOG_ASSERT(cachedNode, "updateCursorBounds: cachedNode cannot be null");
796 LOG_ASSERT(cachedFrame, "updateCursorBounds: cachedFrame cannot be null");
797 gCursorBoundsMutex.lock();
798 m_hasCursorBounds = !cachedNode->isHidden();
799 // If m_hasCursorBounds is false, we never look at the other
800 // values, so do not bother setting them.
801 if (m_hasCursorBounds) {
802 WebCore::IntRect bounds = cachedNode->bounds(cachedFrame);
803 if (m_cursorBounds != bounds)
804 DBG_NAV_LOGD("new cursor bounds=(%d,%d,w=%d,h=%d)",
805 bounds.x(), bounds.y(), bounds.width(), bounds.height());
806 m_cursorBounds = bounds;
807 m_cursorHitBounds = cachedNode->hitBounds(cachedFrame);
808 m_cursorFrame = cachedFrame->framePointer();
809 root->getSimulatedMousePosition(&m_cursorLocation);
810 m_cursorNode = cachedNode->nodePointer();
812 gCursorBoundsMutex.unlock();
815 void WebViewCore::clearContent()
819 m_addInval.setEmpty();
820 m_rebuildInval.setEmpty();
823 bool WebViewCore::focusBoundsChanged()
825 bool result = m_focusBoundsChanged;
826 m_focusBoundsChanged = false;
830 SkPicture* WebViewCore::rebuildPicture(const SkIRect& inval)
832 WebCore::FrameView* view = m_mainFrame->view();
833 int width = view->contentsWidth();
834 int height = view->contentsHeight();
835 SkPicture* picture = new SkPicture();
836 SkAutoPictureRecord arp(picture, width, height, PICT_RECORD_FLAGS);
837 SkAutoMemoryUsageProbe mup(__FUNCTION__);
838 SkCanvas* recordingCanvas = arp.getRecordingCanvas();
841 WTF::Vector<Container> buttons(m_buttons);
842 gButtonMutex.unlock();
844 WebCore::PlatformGraphicsContext pgc(recordingCanvas, &buttons);
845 WebCore::GraphicsContext gc(&pgc);
846 recordingCanvas->translate(-inval.fLeft, -inval.fTop);
847 recordingCanvas->save();
848 view->platformWidget()->draw(&gc, WebCore::IntRect(inval.fLeft,
849 inval.fTop, inval.width(), inval.height()));
850 m_rebuildInval.op(inval, SkRegion::kUnion_Op);
851 DBG_SET_LOGD("m_rebuildInval={%d,%d,r=%d,b=%d}",
852 m_rebuildInval.getBounds().fLeft, m_rebuildInval.getBounds().fTop,
853 m_rebuildInval.getBounds().fRight, m_rebuildInval.getBounds().fBottom);
856 updateButtonList(&buttons);
857 gButtonMutex.unlock();
862 void WebViewCore::rebuildPictureSet(PictureSet* pictureSet)
864 WebCore::FrameView* view = m_mainFrame->view();
865 size_t size = pictureSet->size();
866 for (size_t index = 0; index < size; index++) {
867 if (pictureSet->upToDate(index))
869 const SkIRect& inval = pictureSet->bounds(index);
870 DBG_SET_LOGD("pictSet=%p [%d] {%d,%d,w=%d,h=%d}", pictureSet, index,
871 inval.fLeft, inval.fTop, inval.width(), inval.height());
872 pictureSet->setPicture(index, rebuildPicture(inval));
874 pictureSet->validate(__FUNCTION__);
877 BaseLayerAndroid* WebViewCore::createBaseLayer()
879 BaseLayerAndroid* base = new BaseLayerAndroid();
880 base->setContent(m_content);
882 bool layoutSucceeded = layoutIfNeededRecursive(m_mainFrame);
883 // Layout only fails if called during a layout.
884 LOG_ASSERT(layoutSucceeded, "Can never be called recursively");
886 #if USE(ACCELERATED_COMPOSITING)
887 // We set the background color
888 if (m_mainFrame && m_mainFrame->document()
889 && m_mainFrame->document()->body()) {
890 Document* document = m_mainFrame->document();
891 RefPtr<RenderStyle> style = document->styleForElementIgnoringPendingStylesheets(document->body());
892 if (style->hasBackground()) {
893 Color color = style->visitedDependentColor(CSSPropertyBackgroundColor);
894 if (color.isValid() && color.alpha() > 0)
895 base->setBackgroundColor(color);
899 // We update the layers
900 ChromeClientAndroid* chromeC = static_cast<ChromeClientAndroid*>(m_mainFrame->page()->chrome()->client());
901 GraphicsLayerAndroid* root = static_cast<GraphicsLayerAndroid*>(chromeC->layersSync());
903 root->notifyClientAnimationStarted();
904 LayerAndroid* copyLayer = new LayerAndroid(*root->contentLayer());
905 base->addChild(copyLayer);
913 BaseLayerAndroid* WebViewCore::recordContent(SkRegion* region, SkIPoint* point)
915 DBG_SET_LOG("start");
916 // If there is a pending style recalculation, just return.
917 if (m_mainFrame->document()->isPendingStyleRecalc()) {
918 DBG_SET_LOGD("recordContent: pending style recalc, ignoring.");
921 float progress = (float) m_mainFrame->page()->progress()->estimatedProgress();
922 m_progressDone = progress <= 0.0f || progress >= 1.0f;
923 recordPictureSet(&m_content);
924 if (!m_progressDone && m_content.isEmpty()) {
925 DBG_SET_LOGD("empty (progress=%g)", progress);
928 region->set(m_addInval);
929 m_addInval.setEmpty();
930 region->op(m_rebuildInval, SkRegion::kUnion_Op);
931 m_rebuildInval.setEmpty();
932 point->fX = m_content.width();
933 point->fY = m_content.height();
934 DBG_SET_LOGD("region={%d,%d,r=%d,b=%d}", region->getBounds().fLeft,
935 region->getBounds().fTop, region->getBounds().fRight,
936 region->getBounds().fBottom);
939 return createBaseLayer();
942 void WebViewCore::splitContent(PictureSet* content)
944 bool layoutSucceeded = layoutIfNeededRecursive(m_mainFrame);
945 LOG_ASSERT(layoutSucceeded, "Can never be called recursively");
946 content->split(&m_content);
947 rebuildPictureSet(&m_content);
948 content->set(m_content);
951 void WebViewCore::scrollTo(int x, int y, bool animate)
953 LOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!");
955 // LOGD("WebViewCore::scrollTo(%d %d)\n", x, y);
957 JNIEnv* env = JSC::Bindings::getJNIEnv();
958 env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_scrollTo,
959 x, y, animate, false);
963 void WebViewCore::sendNotifyProgressFinished()
965 LOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!");
966 JNIEnv* env = JSC::Bindings::getJNIEnv();
967 env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_sendNotifyProgressFinished);
971 void WebViewCore::viewInvalidate(const WebCore::IntRect& rect)
973 LOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!");
974 JNIEnv* env = JSC::Bindings::getJNIEnv();
975 env->CallVoidMethod(m_javaGlue->object(env).get(),
976 m_javaGlue->m_sendViewInvalidate,
977 rect.x(), rect.y(), rect.right(), rect.bottom());
981 void WebViewCore::contentDraw()
983 JNIEnv* env = JSC::Bindings::getJNIEnv();
984 env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_contentDraw);
988 void WebViewCore::layersDraw()
990 JNIEnv* env = JSC::Bindings::getJNIEnv();
991 env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_layersDraw);
995 void WebViewCore::contentInvalidate(const WebCore::IntRect &r)
997 DBG_SET_LOGD("rect={%d,%d,w=%d,h=%d}", r.x(), r.y(), r.width(), r.height());
999 if (!rect.intersect(0, 0, INT_MAX, INT_MAX))
1001 m_addInval.op(rect, SkRegion::kUnion_Op);
1002 DBG_SET_LOGD("m_addInval={%d,%d,r=%d,b=%d}",
1003 m_addInval.getBounds().fLeft, m_addInval.getBounds().fTop,
1004 m_addInval.getBounds().fRight, m_addInval.getBounds().fBottom);
1005 if (!m_skipContentDraw)
1009 void WebViewCore::contentInvalidateAll()
1011 WebCore::FrameView* view = m_mainFrame->view();
1012 contentInvalidate(WebCore::IntRect(0, 0,
1013 view->contentsWidth(), view->contentsHeight()));
1016 void WebViewCore::offInvalidate(const WebCore::IntRect &r)
1018 // FIXME: these invalidates are offscreen, and can be throttled or
1019 // deferred until the area is visible. For now, treat them as
1020 // regular invals so that drawing happens (inefficiently) for now.
1021 contentInvalidate(r);
1024 static int pin_pos(int x, int width, int targetWidth)
1026 if (x + width > targetWidth)
1027 x = targetWidth - width;
1033 void WebViewCore::didFirstLayout()
1035 DEBUG_NAV_UI_LOGD("%s", __FUNCTION__);
1036 LOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!");
1038 WebCore::FrameLoader* loader = m_mainFrame->loader();
1039 const WebCore::KURL& url = loader->url();
1042 LOGV("::WebCore:: didFirstLayout %s", url.string().ascii().data());
1044 WebCore::FrameLoadType loadType = loader->loadType();
1046 JNIEnv* env = JSC::Bindings::getJNIEnv();
1047 env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_didFirstLayout,
1048 loadType == WebCore::FrameLoadTypeStandard
1049 // When redirect with locked history, we would like to reset the
1050 // scale factor. This is important for www.yahoo.com as it is
1051 // redirected to www.yahoo.com/?rs=1 on load.
1052 || loadType == WebCore::FrameLoadTypeRedirectWithLockedBackForwardList);
1053 checkException(env);
1055 DBG_NAV_LOG("call updateFrameCache");
1056 m_check_domtree_version = false;
1058 m_history.setDidFirstLayout(true);
1061 void WebViewCore::updateViewport()
1063 DEBUG_NAV_UI_LOGD("%s", __FUNCTION__);
1064 LOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!");
1066 JNIEnv* env = JSC::Bindings::getJNIEnv();
1067 env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_updateViewport);
1068 checkException(env);
1071 void WebViewCore::restoreScale(float scale, float textWrapScale)
1073 DEBUG_NAV_UI_LOGD("%s", __FUNCTION__);
1074 LOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!");
1076 JNIEnv* env = JSC::Bindings::getJNIEnv();
1077 env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_restoreScale, scale, textWrapScale);
1078 checkException(env);
1081 void WebViewCore::needTouchEvents(bool need)
1083 DEBUG_NAV_UI_LOGD("%s", __FUNCTION__);
1084 LOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!");
1086 #if ENABLE(TOUCH_EVENTS)
1087 if (m_forwardingTouchEvents == need)
1090 JNIEnv* env = JSC::Bindings::getJNIEnv();
1091 env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_needTouchEvents, need);
1092 checkException(env);
1094 m_forwardingTouchEvents = need;
1098 void WebViewCore::requestKeyboardWithSelection(const WebCore::Node* node,
1099 int selStart, int selEnd)
1101 DEBUG_NAV_UI_LOGD("%s", __FUNCTION__);
1102 LOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!");
1104 JNIEnv* env = JSC::Bindings::getJNIEnv();
1105 env->CallVoidMethod(m_javaGlue->object(env).get(),
1106 m_javaGlue->m_requestKeyboardWithSelection,
1107 reinterpret_cast<int>(node), selStart, selEnd, m_textGeneration);
1108 checkException(env);
1111 void WebViewCore::requestKeyboard(bool showKeyboard)
1113 DEBUG_NAV_UI_LOGD("%s", __FUNCTION__);
1114 LOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!");
1116 JNIEnv* env = JSC::Bindings::getJNIEnv();
1117 env->CallVoidMethod(m_javaGlue->object(env).get(),
1118 m_javaGlue->m_requestKeyboard, showKeyboard);
1119 checkException(env);
1122 void WebViewCore::notifyProgressFinished()
1124 m_check_domtree_version = true;
1125 sendNotifyProgressFinished();
1128 void WebViewCore::doMaxScroll(CacheBuilder::Direction dir)
1133 case CacheBuilder::LEFT:
1136 case CacheBuilder::UP:
1139 case CacheBuilder::RIGHT:
1142 case CacheBuilder::DOWN:
1145 case CacheBuilder::UNINITIALIZED:
1147 LOG_ASSERT(0, "unexpected focus selector");
1149 WebCore::FrameView* view = m_mainFrame->view();
1150 this->scrollTo(view->scrollX() + dx, view->scrollY() + dy, true);
1153 void WebViewCore::setScrollOffset(int moveGeneration, bool sendScrollEvent, int dx, int dy)
1155 DBG_NAV_LOGD("{%d,%d} m_scrollOffset=(%d,%d), sendScrollEvent=%d", dx, dy,
1156 m_scrollOffsetX, m_scrollOffsetY, sendScrollEvent);
1157 if (m_scrollOffsetX != dx || m_scrollOffsetY != dy) {
1158 m_scrollOffsetX = dx;
1159 m_scrollOffsetY = dy;
1160 // The visible rect is located within our coordinate space so it
1161 // contains the actual scroll position. Setting the location makes hit
1162 // testing work correctly.
1163 m_mainFrame->view()->platformWidget()->setLocation(m_scrollOffsetX,
1165 if (sendScrollEvent) {
1166 m_mainFrame->eventHandler()->sendScrollEvent();
1168 // Only update history position if it's user scrolled.
1169 // Update history item to reflect the new scroll position.
1170 // This also helps save the history information when the browser goes to
1171 // background, so scroll position will be restored if browser gets
1172 // killed while in background.
1173 WebCore::HistoryController* history = m_mainFrame->loader()->history();
1174 // Because the history item saving could be heavy for large sites and
1175 // scrolling can generate lots of small scroll offset, the following code
1176 // reduces the saving frequency.
1177 static const int MIN_SCROLL_DIFF = 32;
1178 if (history->currentItem()) {
1179 WebCore::IntPoint currentPoint = history->currentItem()->scrollPoint();
1180 if (std::abs(currentPoint.x() - dx) >= MIN_SCROLL_DIFF ||
1181 std::abs(currentPoint.y() - dy) >= MIN_SCROLL_DIFF) {
1182 history->saveScrollPositionAndViewStateToItem(history->currentItem());
1187 // update the currently visible screen
1188 sendPluginVisibleScreen();
1190 gCursorBoundsMutex.lock();
1191 bool hasCursorBounds = m_hasCursorBounds;
1192 Frame* frame = (Frame*) m_cursorFrame;
1193 IntPoint location = m_cursorLocation;
1194 gCursorBoundsMutex.unlock();
1195 if (!hasCursorBounds)
1197 moveMouseIfLatest(moveGeneration, frame, location.x(), location.y());
1200 void WebViewCore::setGlobalBounds(int x, int y, int h, int v)
1202 DBG_NAV_LOGD("{%d,%d}", x, y);
1203 m_mainFrame->view()->platformWidget()->setWindowBounds(x, y, h, v);
1206 void WebViewCore::setSizeScreenWidthAndScale(int width, int height,
1207 int textWrapWidth, float scale, int screenWidth, int screenHeight,
1208 int anchorX, int anchorY, bool ignoreHeight)
1210 WebCoreViewBridge* window = m_mainFrame->view()->platformWidget();
1211 int ow = window->width();
1212 int oh = window->height();
1213 int osw = m_screenWidth;
1214 int osh = m_screenHeight;
1215 int otw = m_textWrapWidth;
1216 float oldScale = m_scale;
1217 DBG_NAV_LOGD("old:(w=%d,h=%d,sw=%d,scale=%g) new:(w=%d,h=%d,sw=%d,scale=%g)",
1218 ow, oh, osw, m_scale, width, height, screenWidth, scale);
1219 m_screenWidth = screenWidth;
1220 m_screenHeight = screenHeight;
1221 m_textWrapWidth = textWrapWidth;
1222 if (scale >= 0) // negative means keep the current scale
1224 m_maxXScroll = screenWidth >> 2;
1225 m_maxYScroll = m_maxXScroll * height / width;
1226 // Don't reflow if the diff is small.
1227 const bool reflow = otw && textWrapWidth &&
1228 ((float) abs(otw - textWrapWidth) / textWrapWidth) >= 0.01f;
1230 // When the screen size change, fixed positioned element should be updated.
1231 // This is supposed to be light weighted operation without a full layout.
1232 if (osh != screenHeight || osw != screenWidth)
1233 m_mainFrame->view()->updatePositionedObjects();
1235 if (ow != width || (!ignoreHeight && oh != height) || reflow) {
1236 WebCore::RenderObject *r = m_mainFrame->contentRenderer();
1237 DBG_NAV_LOGD("renderer=%p view=(w=%d,h=%d)", r,
1238 screenWidth, screenHeight);
1240 WebCore::IntPoint anchorPoint = WebCore::IntPoint(anchorX, anchorY);
1241 DBG_NAV_LOGD("anchorX=%d anchorY=%d", anchorX, anchorY);
1242 RefPtr<WebCore::Node> node;
1243 WebCore::IntRect bounds;
1244 WebCore::IntPoint offset;
1245 // If the text wrap changed, it is probably zoom change or
1246 // orientation change. Try to keep the anchor at the same place.
1247 if (otw && textWrapWidth && otw != textWrapWidth &&
1248 (anchorX != 0 || anchorY != 0)) {
1249 WebCore::HitTestResult hitTestResult =
1250 m_mainFrame->eventHandler()->hitTestResultAtPoint(
1251 anchorPoint, false);
1252 node = hitTestResult.innerNode();
1255 bounds = node->getRect();
1256 DBG_NAV_LOGD("ob:(x=%d,y=%d,w=%d,h=%d)",
1257 bounds.x(), bounds.y(), bounds.width(), bounds.height());
1258 // sites like nytimes.com insert a non-standard tag <nyt_text>
1259 // in the html. If it is the HitTestResult, it may have zero
1260 // width and height. In this case, use its parent node.
1261 if (bounds.width() == 0) {
1262 node = node->parentOrHostNode();
1264 bounds = node->getRect();
1265 DBG_NAV_LOGD("found a zero width node and use its parent, whose ob:(x=%d,y=%d,w=%d,h=%d)",
1266 bounds.x(), bounds.y(), bounds.width(), bounds.height());
1271 // Set the size after finding the old anchor point as
1272 // hitTestResultAtPoint causes a layout.
1273 window->setSize(width, height);
1274 window->setVisibleSize(screenWidth, screenHeight);
1275 if (width != screenWidth) {
1276 m_mainFrame->view()->setUseFixedLayout(true);
1277 m_mainFrame->view()->setFixedLayoutSize(IntSize(width, height));
1279 m_mainFrame->view()->setUseFixedLayout(false);
1281 r->setNeedsLayoutAndPrefWidthsRecalc();
1282 m_mainFrame->view()->forceLayout();
1284 // scroll to restore current screen center
1286 const WebCore::IntRect& newBounds = node->getRect();
1287 DBG_NAV_LOGD("nb:(x=%d,y=%d,w=%d,"
1288 "h=%d)", newBounds.x(), newBounds.y(),
1289 newBounds.width(), newBounds.height());
1290 if ((osw && osh && bounds.width() && bounds.height())
1291 && (bounds != newBounds)) {
1292 WebCore::FrameView* view = m_mainFrame->view();
1293 // force left align if width is not changed while height changed.
1294 // the anchorPoint is probably at some white space in the node
1295 // which is affected by text wrap around the screen width.
1296 const bool leftAlign = (otw != textWrapWidth)
1297 && (bounds.width() == newBounds.width())
1298 && (bounds.height() != newBounds.height());
1299 const float xPercentInDoc =
1300 leftAlign ? 0.0 : (float) (anchorX - bounds.x()) / bounds.width();
1301 const float xPercentInView =
1302 leftAlign ? 0.0 : (float) (anchorX - m_scrollOffsetX) / osw;
1303 const float yPercentInDoc = (float) (anchorY - bounds.y()) / bounds.height();
1304 const float yPercentInView = (float) (anchorY - m_scrollOffsetY) / osh;
1305 showRect(newBounds.x(), newBounds.y(), newBounds.width(),
1306 newBounds.height(), view->contentsWidth(),
1307 view->contentsHeight(),
1308 xPercentInDoc, xPercentInView,
1309 yPercentInDoc, yPercentInView);
1314 window->setSize(width, height);
1315 window->setVisibleSize(screenWidth, screenHeight);
1316 m_mainFrame->view()->resize(width, height);
1317 if (width != screenWidth) {
1318 m_mainFrame->view()->setUseFixedLayout(true);
1319 m_mainFrame->view()->setFixedLayoutSize(IntSize(width, height));
1321 m_mainFrame->view()->setUseFixedLayout(false);
1325 // update the currently visible screen as perceived by the plugin
1326 sendPluginVisibleScreen();
1329 void WebViewCore::dumpDomTree(bool useFile)
1331 #ifdef ANDROID_DOM_LOGGING
1333 gDomTreeFile = fopen(DOM_TREE_LOG_FILE, "w");
1334 m_mainFrame->document()->showTreeForThis();
1336 fclose(gDomTreeFile);
1342 void WebViewCore::dumpRenderTree(bool useFile)
1344 #ifdef ANDROID_DOM_LOGGING
1345 WTF::CString renderDump = WebCore::externalRepresentation(m_mainFrame).utf8();
1346 const char* data = renderDump.data();
1348 gRenderTreeFile = fopen(RENDER_TREE_LOG_FILE, "w");
1349 DUMP_RENDER_LOGD("%s", data);
1350 fclose(gRenderTreeFile);
1351 gRenderTreeFile = 0;
1353 // adb log can only output 1024 characters, so write out line by line.
1354 // exclude '\n' as adb log adds it for each output.
1355 int length = renderDump.length();
1356 for (int i = 0, last = 0; i < length; i++) {
1357 if (data[i] == '\n') {
1359 DUMP_RENDER_LOGD("%.*s", (i - last), &(data[last]));
1367 void WebViewCore::dumpNavTree()
1370 cacheBuilder().mDebug.print();
1374 HTMLElement* WebViewCore::retrieveElement(int x, int y,
1375 const QualifiedName& tagName)
1377 HitTestResult hitTestResult = m_mainFrame->eventHandler()
1378 ->hitTestResultAtPoint(IntPoint(x, y), false, false,
1379 DontHitTestScrollbars, HitTestRequest::Active | HitTestRequest::ReadOnly,
1381 if (!hitTestResult.innerNode() || !hitTestResult.innerNode()->inDocument()) {
1382 LOGE("Should not happen: no in document Node found");
1385 const ListHashSet<RefPtr<Node> >& list = hitTestResult.rectBasedTestResult();
1386 if (list.isEmpty()) {
1387 LOGE("Should not happen: no rect-based-test nodes found");
1390 Node* node = hitTestResult.innerNode();
1391 Node* element = node;
1392 while (element && (!element->isElementNode()
1393 || !element->hasTagName(tagName))) {
1394 element = element->parentNode();
1396 DBG_NAV_LOGD("node=%p element=%p x=%d y=%d nodeName=%s tagName=%s", node,
1397 element, x, y, node->nodeName().utf8().data(),
1398 element ? ((Element*) element)->tagName().utf8().data() : "<none>");
1399 return static_cast<WebCore::HTMLElement*>(element);
1402 HTMLAnchorElement* WebViewCore::retrieveAnchorElement(int x, int y)
1404 return static_cast<HTMLAnchorElement*>
1405 (retrieveElement(x, y, HTMLNames::aTag));
1408 HTMLImageElement* WebViewCore::retrieveImageElement(int x, int y)
1410 return static_cast<HTMLImageElement*>
1411 (retrieveElement(x, y, HTMLNames::imgTag));
1414 WTF::String WebViewCore::retrieveHref(int x, int y)
1416 WebCore::HTMLAnchorElement* anchor = retrieveAnchorElement(x, y);
1417 return anchor ? anchor->href() : WTF::String();
1420 WTF::String WebViewCore::retrieveAnchorText(int x, int y)
1422 WebCore::HTMLAnchorElement* anchor = retrieveAnchorElement(x, y);
1423 return anchor ? anchor->text() : WTF::String();
1426 WTF::String WebViewCore::retrieveImageSource(int x, int y)
1428 HTMLImageElement* image = retrieveImageElement(x, y);
1429 return image ? image->src().string() : WTF::String();
1432 WTF::String WebViewCore::requestLabel(WebCore::Frame* frame,
1433 WebCore::Node* node)
1435 if (node && CacheBuilder::validNode(m_mainFrame, frame, node)) {
1436 RefPtr<WebCore::NodeList> list = node->document()->getElementsByTagName("label");
1437 unsigned length = list->length();
1438 for (unsigned i = 0; i < length; i++) {
1439 WebCore::HTMLLabelElement* label = static_cast<WebCore::HTMLLabelElement*>(
1441 if (label->control() == node) {
1444 while ((node = node->traverseNextNode(label))) {
1445 if (node->isTextNode()) {
1446 Text* textNode = static_cast<Text*>(node);
1447 result += textNode->dataImpl();
1454 return WTF::String();
1457 static bool isContentEditable(const WebCore::Node* node)
1459 if (!node) return false;
1460 return node->document()->frame()->selection()->isContentEditable();
1463 // Returns true if the node is a textfield, textarea, or contentEditable
1464 static bool isTextInput(const WebCore::Node* node)
1466 if (isContentEditable(node))
1470 WebCore::RenderObject* renderer = node->renderer();
1471 return renderer && (renderer->isTextField() || renderer->isTextArea());
1474 void WebViewCore::revealSelection()
1476 WebCore::Node* focus = currentFocus();
1479 if (!isTextInput(focus))
1481 WebCore::Frame* focusedFrame = focus->document()->frame();
1482 if (!focusedFrame->page()->focusController()->isActive())
1484 focusedFrame->selection()->revealSelection(ScrollAlignment::alignToEdgeIfNeeded);
1487 void WebViewCore::updateCacheOnNodeChange()
1489 gCursorBoundsMutex.lock();
1490 bool hasCursorBounds = m_hasCursorBounds;
1491 Frame* frame = (Frame*) m_cursorFrame;
1492 Node* node = (Node*) m_cursorNode;
1493 IntRect bounds = m_cursorHitBounds;
1494 gCursorBoundsMutex.unlock();
1495 if (!hasCursorBounds || !node)
1497 if (CacheBuilder::validNode(m_mainFrame, frame, node)) {
1498 RenderObject* renderer = node->renderer();
1499 if (renderer && renderer->style()->visibility() != HIDDEN) {
1500 IntRect absBox = renderer->absoluteBoundingBoxRect();
1501 int globalX, globalY;
1502 CacheBuilder::GetGlobalOffset(frame, &globalX, &globalY);
1503 absBox.move(globalX, globalY);
1504 if (absBox == bounds)
1506 DBG_NAV_LOGD("absBox=(%d,%d,%d,%d) bounds=(%d,%d,%d,%d)",
1507 absBox.x(), absBox.y(), absBox.width(), absBox.height(),
1508 bounds.x(), bounds.y(), bounds.width(), bounds.height());
1511 DBG_NAV_LOGD("updateFrameCache node=%p", node);
1515 void WebViewCore::updateFrameCache()
1517 if (!m_frameCacheOutOfDate) {
1518 DBG_NAV_LOG("!m_frameCacheOutOfDate");
1522 // If there is a pending style recalculation, do not update the frame cache.
1523 // Until the recalculation is complete, there may be internal objects that
1524 // are in an inconsistent state (such as font pointers).
1525 // In any event, there's not much point to updating the cache while a style
1526 // recalculation is pending, since it will simply have to be updated again
1527 // once the recalculation is complete.
1528 // TODO: Do we need to reschedule an update for after the style is recalculated?
1529 if (m_mainFrame && m_mainFrame->document() && m_mainFrame->document()->isPendingStyleRecalc()) {
1530 LOGW("updateFrameCache: pending style recalc, ignoring.");
1533 #ifdef ANDROID_INSTRUMENT
1534 TimeCounterAuto counter(TimeCounter::WebViewCoreBuildNavTimeCounter);
1536 m_frameCacheOutOfDate = false;
1538 m_now = SkTime::GetMSecs();
1540 m_temp = new CachedRoot();
1541 m_temp->init(m_mainFrame, &m_history);
1542 #if USE(ACCELERATED_COMPOSITING)
1543 GraphicsLayerAndroid* graphicsLayer = graphicsRootLayer();
1545 m_temp->setRootLayer(graphicsLayer->contentLayer());
1547 CacheBuilder& builder = cacheBuilder();
1548 WebCore::Settings* settings = m_mainFrame->page()->settings();
1549 builder.allowAllTextDetection();
1550 #ifdef ANDROID_META_SUPPORT
1552 if (!settings->formatDetectionAddress())
1553 builder.disallowAddressDetection();
1554 if (!settings->formatDetectionEmail())
1555 builder.disallowEmailDetection();
1556 if (!settings->formatDetectionTelephone())
1557 builder.disallowPhoneDetection();
1560 builder.buildCache(m_temp);
1561 m_tempPict = new SkPicture();
1562 recordPicture(m_tempPict);
1563 m_temp->setPicture(m_tempPict);
1564 m_temp->setTextGeneration(m_textGeneration);
1565 WebCoreViewBridge* window = m_mainFrame->view()->platformWidget();
1566 m_temp->setVisibleRect(WebCore::IntRect(m_scrollOffsetX,
1567 m_scrollOffsetY, window->width(), window->height()));
1568 gFrameCacheMutex.lock();
1569 delete m_frameCacheKit;
1570 delete m_navPictureKit;
1571 m_frameCacheKit = m_temp;
1572 m_navPictureKit = m_tempPict;
1573 m_updatedFrameCache = true;
1575 const CachedNode* cachedFocusNode = m_frameCacheKit->currentFocus();
1576 DBG_NAV_LOGD("cachedFocusNode=%d (nodePointer=%p)",
1577 cachedFocusNode ? cachedFocusNode->index() : 0,
1578 cachedFocusNode ? cachedFocusNode->nodePointer() : 0);
1580 gFrameCacheMutex.unlock();
1583 void WebViewCore::updateFrameCacheIfLoading()
1585 if (!m_check_domtree_version)
1589 struct TouchNodeData {
1594 // get the bounding box of the Node
1595 static IntRect getAbsoluteBoundingBox(Node* node) {
1597 RenderObject* render = node->renderer();
1598 if (render->isRenderInline())
1599 rect = toRenderInline(render)->linesVisualOverflowBoundingBox();
1600 else if (render->isBox())
1601 rect = toRenderBox(render)->visualOverflowRect();
1602 else if (render->isText())
1603 rect = toRenderText(render)->linesBoundingBox();
1605 LOGE("getAbsoluteBoundingBox failed for node %p, name %s", node, render->renderName());
1606 FloatPoint absPos = render->localToAbsolute();
1607 rect.move(absPos.x(), absPos.y());
1611 // get the highlight rectangles for the touch point (x, y) with the slop
1612 Vector<IntRect> WebViewCore::getTouchHighlightRects(int x, int y, int slop)
1614 Vector<IntRect> rects;
1615 m_mousePos = IntPoint(x - m_scrollOffsetX, y - m_scrollOffsetY);
1616 HitTestResult hitTestResult = m_mainFrame->eventHandler()->hitTestResultAtPoint(IntPoint(x, y),
1617 false, false, DontHitTestScrollbars, HitTestRequest::Active | HitTestRequest::ReadOnly, IntSize(slop, slop));
1618 if (!hitTestResult.innerNode() || !hitTestResult.innerNode()->inDocument()) {
1619 LOGE("Should not happen: no in document Node found");
1622 const ListHashSet<RefPtr<Node> >& list = hitTestResult.rectBasedTestResult();
1623 if (list.isEmpty()) {
1624 LOGE("Should not happen: no rect-based-test nodes found");
1627 Frame* frame = hitTestResult.innerNode()->document()->frame();
1628 Vector<TouchNodeData> nodeDataList;
1629 ListHashSet<RefPtr<Node> >::const_iterator last = list.end();
1630 for (ListHashSet<RefPtr<Node> >::const_iterator it = list.begin(); it != last; ++it) {
1631 // TODO: it seems reasonable to not search across the frame. Isn't it?
1632 // if the node is not in the same frame as the innerNode, skip it
1633 if (it->get()->document()->frame() != frame)
1635 // traverse up the tree to find the first node that needs highlight
1637 Node* eventNode = it->get();
1639 RenderObject* render = eventNode->renderer();
1640 if (render->isBody() || render->isRenderView())
1642 if (eventNode->supportsFocus()
1643 || eventNode->hasEventListeners(eventNames().clickEvent)
1644 || eventNode->hasEventListeners(eventNames().mousedownEvent)
1645 || eventNode->hasEventListeners(eventNames().mouseupEvent)) {
1649 // the nodes in the rectBasedTestResult() are ordered based on z-index during hit testing.
1650 // so do not search for the eventNode across explicit z-index border.
1651 // TODO: this is a hard one to call. z-index is quite complicated as its value only
1652 // matters when you compare two RenderLayer in the same hierarchy level. e.g. in
1653 // the following example, "b" is on the top as its z level is the highest. even "c"
1654 // has 100 as z-index, it is still below "d" as its parent has the same z-index as
1655 // "d" and logically before "d". Of course "a" is the lowest in the z level.
1663 // If the fat point touches everyone, the order in the list should be "b", "d", "c"
1664 // and "a". When we search for the event node for "b", we really don't want "a" as
1665 // in the z-order it is behind everything else.
1666 if (!render->style()->hasAutoZIndex())
1668 eventNode = eventNode->parentNode();
1670 // didn't find any eventNode, skip it
1673 // first quick check whether it is a duplicated node before computing bounding box
1674 Vector<TouchNodeData>::const_iterator nlast = nodeDataList.end();
1675 for (Vector<TouchNodeData>::const_iterator n = nodeDataList.begin(); n != nlast; ++n) {
1676 // found the same node, skip it
1677 if (eventNode == n->mNode) {
1684 // next check whether the node is fully covered by or fully covering another node.
1686 IntRect rect = getAbsoluteBoundingBox(eventNode);
1687 if (rect.isEmpty()) {
1688 // if the node's bounds is empty and it is not a ContainerNode, skip it.
1689 if (!eventNode->isContainerNode())
1691 // if the node's children are all positioned objects, its bounds can be empty.
1692 // Walk through the children to find the bounding box.
1693 Node* child = static_cast<const ContainerNode*>(eventNode)->firstChild();
1696 if (child->renderer())
1697 childrect = getAbsoluteBoundingBox(child);
1698 if (!childrect.isEmpty()) {
1699 rect.unite(childrect);
1700 child = child->traverseNextSibling(eventNode);
1702 child = child->traverseNextNode(eventNode);
1705 for (int i = nodeDataList.size() - 1; i >= 0; i--) {
1706 TouchNodeData n = nodeDataList.at(i);
1707 // the new node is enclosing an existing node, skip it
1708 if (rect.contains(n.mBounds)) {
1712 // the new node is fully inside an existing node, remove the existing node
1713 if (n.mBounds.contains(rect))
1714 nodeDataList.remove(i);
1717 TouchNodeData newNode;
1718 newNode.mNode = eventNode;
1719 newNode.mBounds = rect;
1720 nodeDataList.append(newNode);
1723 if (!nodeDataList.size())
1725 // finally select the node with the largest overlap with the fat point
1726 TouchNodeData final;
1728 IntPoint docPos = frame->view()->windowToContents(m_mousePos);
1729 IntRect testRect(docPos.x() - slop, docPos.y() - slop, 2 * slop + 1, 2 * slop + 1);
1731 Vector<TouchNodeData>::const_iterator nlast = nodeDataList.end();
1732 for (Vector<TouchNodeData>::const_iterator n = nodeDataList.begin(); n != nlast; ++n) {
1733 IntRect rect = n->mBounds;
1734 rect.intersect(testRect);
1735 int a = rect.width() * rect.height();
1741 // now get the node's highlight rectangles in the page coordinate system
1743 IntPoint frameAdjust;
1744 if (frame != m_mainFrame) {
1745 frameAdjust = frame->view()->contentsToWindow(IntPoint());
1746 frameAdjust.move(m_scrollOffsetX, m_scrollOffsetY);
1748 if (final.mNode->isLink()) {
1749 // most of the links are inline instead of box style. So the bounding box is not
1750 // a good representation for the highlights. Get the list of rectangles instead.
1751 RenderObject* render = final.mNode->renderer();
1752 IntPoint offset = roundedIntPoint(render->localToAbsolute());
1753 render->absoluteRects(rects, offset.x() + frameAdjust.x(), offset.y() + frameAdjust.y());
1754 bool inside = false;
1755 int distance = INT_MAX;
1756 int newx = x, newy = y;
1757 int i = rects.size();
1759 if (rects[i].isEmpty()) {
1763 // check whether the point (x, y) is inside one of the rectangles.
1766 if (rects[i].contains(x, y)) {
1770 if (x >= rects[i].x() && x < rects[i].right()) {
1771 if (y < rects[i].y()) {
1772 if (rects[i].y() - y < distance) {
1774 newy = rects[i].y();
1775 distance = rects[i].y() - y;
1777 } else if (y >= rects[i].bottom()) {
1778 if (y - rects[i].bottom() + 1 < distance) {
1780 newy = rects[i].bottom() - 1;
1781 distance = y - rects[i].bottom() + 1;
1784 } else if (y >= rects[i].y() && y < rects[i].bottom()) {
1785 if (x < rects[i].x()) {
1786 if (rects[i].x() - x < distance) {
1787 newx = rects[i].x();
1789 distance = rects[i].x() - x;
1791 } else if (x >= rects[i].right()) {
1792 if (x - rects[i].right() + 1 < distance) {
1793 newx = rects[i].right() - 1;
1795 distance = x - rects[i].right() + 1;
1800 if (!rects.isEmpty()) {
1802 // if neither x nor y has overlap, just pick the top/left of the first rectangle
1803 if (newx == x && newy == y) {
1804 newx = rects[0].x();
1805 newy = rects[0].y();
1807 m_mousePos.setX(newx - m_scrollOffsetX);
1808 m_mousePos.setY(newy - m_scrollOffsetY);
1809 DBG_NAV_LOGD("Move x/y from (%d, %d) to (%d, %d) scrollOffset is (%d, %d)",
1810 x, y, m_mousePos.x() + m_scrollOffsetX, m_mousePos.y() + m_scrollOffsetY,
1811 m_scrollOffsetX, m_scrollOffsetY);
1816 IntRect rect = final.mBounds;
1817 rect.move(frameAdjust.x(), frameAdjust.y());
1819 // adjust m_mousePos if it is not inside the returned highlight rectangle
1820 testRect.move(frameAdjust.x(), frameAdjust.y());
1821 testRect.intersect(rect);
1822 if (!testRect.contains(x, y)) {
1823 m_mousePos = testRect.center();
1824 m_mousePos.move(-m_scrollOffsetX, -m_scrollOffsetY);
1825 DBG_NAV_LOGD("Move x/y from (%d, %d) to (%d, %d) scrollOffset is (%d, %d)",
1826 x, y, m_mousePos.x() + m_scrollOffsetX, m_mousePos.y() + m_scrollOffsetY,
1827 m_scrollOffsetX, m_scrollOffsetY);
1833 ///////////////////////////////////////////////////////////////////////////////
1835 void WebViewCore::addPlugin(PluginWidgetAndroid* w)
1837 // SkDebugf("----------- addPlugin %p", w);
1838 /* The plugin must be appended to the end of the array. This ensures that if
1839 the plugin is added while iterating through the array (e.g. sendEvent(...))
1840 that the iteration process is not corrupted.
1842 *m_plugins.append() = w;
1845 void WebViewCore::removePlugin(PluginWidgetAndroid* w)
1847 // SkDebugf("----------- removePlugin %p", w);
1848 int index = m_plugins.find(w);
1850 SkDebugf("--------------- pluginwindow not found! %p\n", w);
1852 m_plugins.removeShuffle(index);
1856 bool WebViewCore::isPlugin(PluginWidgetAndroid* w) const
1858 return m_plugins.find(w) >= 0;
1861 void WebViewCore::invalPlugin(PluginWidgetAndroid* w)
1863 const double PLUGIN_INVAL_DELAY = 1.0 / 60;
1865 if (!m_pluginInvalTimer.isActive()) {
1866 m_pluginInvalTimer.startOneShot(PLUGIN_INVAL_DELAY);
1870 void WebViewCore::drawPlugins()
1872 SkRegion inval; // accumualte what needs to be redrawn
1873 PluginWidgetAndroid** iter = m_plugins.begin();
1874 PluginWidgetAndroid** stop = m_plugins.end();
1876 for (; iter < stop; ++iter) {
1877 PluginWidgetAndroid* w = *iter;
1879 if (w->isDirty(&dirty)) {
1881 inval.op(dirty, SkRegion::kUnion_Op);
1885 if (!inval.isEmpty()) {
1886 // inval.getBounds() is our rectangle
1887 const SkIRect& bounds = inval.getBounds();
1888 WebCore::IntRect r(bounds.fLeft, bounds.fTop,
1889 bounds.width(), bounds.height());
1890 this->viewInvalidate(r);
1894 void WebViewCore::notifyPluginsOnFrameLoad(const Frame* frame) {
1895 // if frame is the parent then notify all plugins
1896 if (!frame->tree()->parent()) {
1897 // trigger an event notifying the plugins that the page has loaded
1899 SkANP::InitEvent(&event, kLifecycle_ANPEventType);
1900 event.data.lifecycle.action = kOnLoad_ANPLifecycleAction;
1901 sendPluginEvent(event);
1902 // trigger the on/off screen notification if the page was reloaded
1903 sendPluginVisibleScreen();
1905 // else if frame's parent has completed
1906 else if (!frame->tree()->parent()->loader()->isLoading()) {
1907 // send to all plugins who have this frame in their heirarchy
1908 PluginWidgetAndroid** iter = m_plugins.begin();
1909 PluginWidgetAndroid** stop = m_plugins.end();
1910 for (; iter < stop; ++iter) {
1911 Frame* currentFrame = (*iter)->pluginView()->parentFrame();
1912 while (currentFrame) {
1913 if (frame == currentFrame) {
1915 SkANP::InitEvent(&event, kLifecycle_ANPEventType);
1916 event.data.lifecycle.action = kOnLoad_ANPLifecycleAction;
1917 (*iter)->sendEvent(event);
1919 // trigger the on/off screen notification if the page was reloaded
1920 ANPRectI visibleRect;
1921 getVisibleScreen(visibleRect);
1922 (*iter)->setVisibleScreen(visibleRect, m_scale);
1926 currentFrame = currentFrame->tree()->parent();
1932 void WebViewCore::getVisibleScreen(ANPRectI& visibleRect)
1934 visibleRect.left = m_scrollOffsetX;
1935 visibleRect.top = m_scrollOffsetY;
1936 visibleRect.right = m_scrollOffsetX + m_screenWidth;
1937 visibleRect.bottom = m_scrollOffsetY + m_screenHeight;
1940 void WebViewCore::sendPluginVisibleScreen()
1942 /* We may want to cache the previous values and only send the notification
1943 to the plugin in the event that one of the values has changed.
1946 ANPRectI visibleRect;
1947 getVisibleScreen(visibleRect);
1949 PluginWidgetAndroid** iter = m_plugins.begin();
1950 PluginWidgetAndroid** stop = m_plugins.end();
1951 for (; iter < stop; ++iter) {
1952 (*iter)->setVisibleScreen(visibleRect, m_scale);
1956 void WebViewCore::sendPluginEvent(const ANPEvent& evt)
1958 /* The list of plugins may be manipulated as we iterate through the list.
1959 This implementation allows for the addition of new plugins during an
1960 iteration, but may fail if a plugin is removed. Currently, there are not
1961 any use cases where a plugin is deleted while processing this loop, but
1962 if it does occur we will have to use an alternate data structure and/or
1963 iteration mechanism.
1965 for (int x = 0; x < m_plugins.count(); x++) {
1966 m_plugins[x]->sendEvent(evt);
1970 PluginWidgetAndroid* WebViewCore::getPluginWidget(NPP npp)
1972 PluginWidgetAndroid** iter = m_plugins.begin();
1973 PluginWidgetAndroid** stop = m_plugins.end();
1974 for (; iter < stop; ++iter) {
1975 if ((*iter)->pluginView()->instance() == npp) {
1982 static PluginView* nodeIsPlugin(Node* node) {
1983 RenderObject* renderer = node->renderer();
1984 if (renderer && renderer->isWidget()) {
1985 Widget* widget = static_cast<RenderWidget*>(renderer)->widget();
1986 if (widget && widget->isPluginView())
1987 return static_cast<PluginView*>(widget);
1992 Node* WebViewCore::cursorNodeIsPlugin() {
1993 gCursorBoundsMutex.lock();
1994 bool hasCursorBounds = m_hasCursorBounds;
1995 Frame* frame = (Frame*) m_cursorFrame;
1996 Node* node = (Node*) m_cursorNode;
1997 gCursorBoundsMutex.unlock();
1998 if (hasCursorBounds && CacheBuilder::validNode(m_mainFrame, frame, node)
1999 && nodeIsPlugin(node)) {
2005 ///////////////////////////////////////////////////////////////////////////////
2006 void WebViewCore::moveMouseIfLatest(int moveGeneration,
2007 WebCore::Frame* frame, int x, int y)
2009 DBG_NAV_LOGD("m_moveGeneration=%d moveGeneration=%d"
2010 " frame=%p x=%d y=%d",
2011 m_moveGeneration, moveGeneration, frame, x, y);
2012 if (m_moveGeneration > moveGeneration) {
2013 DBG_NAV_LOGD("m_moveGeneration=%d > moveGeneration=%d",
2014 m_moveGeneration, moveGeneration);
2015 return; // short-circuit if a newer move has already been generated
2017 m_lastGeneration = moveGeneration;
2018 moveMouse(frame, x, y);
2021 void WebViewCore::moveFocus(WebCore::Frame* frame, WebCore::Node* node)
2023 DBG_NAV_LOGD("frame=%p node=%p", frame, node);
2024 if (!node || !CacheBuilder::validNode(m_mainFrame, frame, node)
2025 || !node->isElementNode())
2027 // Code borrowed from FocusController::advanceFocus
2028 WebCore::FocusController* focusController
2029 = m_mainFrame->page()->focusController();
2030 WebCore::Document* oldDoc
2031 = focusController->focusedOrMainFrame()->document();
2032 if (oldDoc->focusedNode() == node)
2034 if (node->document() != oldDoc)
2035 oldDoc->setFocusedNode(0);
2036 focusController->setFocusedFrame(frame);
2037 static_cast<WebCore::Element*>(node)->focus(false);
2040 // Update mouse position
2041 void WebViewCore::moveMouse(WebCore::Frame* frame, int x, int y)
2043 DBG_NAV_LOGD("frame=%p x=%d y=%d scrollOffset=(%d,%d)", frame,
2044 x, y, m_scrollOffsetX, m_scrollOffsetY);
2045 if (!frame || !CacheBuilder::validNode(m_mainFrame, frame, 0))
2046 frame = m_mainFrame;
2047 // mouse event expects the position in the window coordinate
2048 m_mousePos = WebCore::IntPoint(x - m_scrollOffsetX, y - m_scrollOffsetY);
2049 // validNode will still return true if the node is null, as long as we have
2050 // a valid frame. Do not want to make a call on frame unless it is valid.
2051 WebCore::PlatformMouseEvent mouseEvent(m_mousePos, m_mousePos,
2052 WebCore::NoButton, WebCore::MouseEventMoved, 1, false, false, false,
2053 false, WTF::currentTime());
2054 frame->eventHandler()->handleMouseMoveEvent(mouseEvent);
2055 updateCacheOnNodeChange();
2058 void WebViewCore::setSelection(int start, int end)
2060 WebCore::Node* focus = currentFocus();
2063 WebCore::RenderObject* renderer = focus->renderer();
2064 if (!renderer || (!renderer->isTextField() && !renderer->isTextArea()))
2071 // Tell our EditorClient that this change was generated from the UI, so it
2072 // does not need to echo it to the UI.
2073 EditorClientAndroid* client = static_cast<EditorClientAndroid*>(
2074 m_mainFrame->editor()->client());
2075 client->setUiGeneratedSelectionChange(true);
2076 setSelectionRange(focus, start, end);
2077 client->setUiGeneratedSelectionChange(false);
2078 WebCore::Frame* focusedFrame = focus->document()->frame();
2079 bool isPasswordField = false;
2080 if (focus->isElementNode()) {
2081 WebCore::Element* element = static_cast<WebCore::Element*>(focus);
2082 if (WebCore::InputElement* inputElement = WebCore::toInputElement(element))
2083 isPasswordField = static_cast<WebCore::HTMLInputElement*>(inputElement)->isPasswordField();
2085 // For password fields, this is done in the UI side via
2086 // bringPointIntoView, since the UI does the drawing.
2087 if (renderer->isTextArea() || !isPasswordField)
2091 String WebViewCore::modifySelection(const int direction, const int axis)
2093 DOMSelection* selection = m_mainFrame->domWindow()->getSelection();
2094 if (selection->rangeCount() > 1)
2095 selection->removeAllRanges();
2097 case AXIS_CHARACTER:
2100 return modifySelectionTextNavigationAxis(selection, direction, axis);
2103 case AXIS_PARENT_FIRST_CHILD:
2105 return modifySelectionDomNavigationAxis(selection, direction, axis);
2107 LOGE("Invalid navigation axis: %d", axis);
2112 void WebViewCore::scrollNodeIntoView(Frame* frame, Node* node)
2114 if (!frame || !node)
2117 Element* elementNode = 0;
2119 // If not an Element, find a visible predecessor
2120 // Element to scroll into view.
2121 if (!node->isElementNode()) {
2122 HTMLElement* body = frame->document()->body();
2124 if (!node || node == body)
2126 node = node->parentNode();
2127 } while (!node->isElementNode() && !isVisible(node));
2130 elementNode = static_cast<Element*>(node);
2131 elementNode->scrollIntoViewIfNeeded(true);
2134 String WebViewCore::modifySelectionTextNavigationAxis(DOMSelection* selection, int direction, int axis)
2136 Node* body = m_mainFrame->document()->body();
2138 ExceptionCode ec = 0;
2141 // initialize the selection if necessary
2142 if (selection->rangeCount() == 0) {
2143 if (m_currentNodeDomNavigationAxis
2144 && CacheBuilder::validNode(m_mainFrame,
2145 m_mainFrame, m_currentNodeDomNavigationAxis)) {
2146 PassRefPtr<Range> rangeRef =
2147 selection->frame()->document()->createRange();
2148 rangeRef->selectNode(m_currentNodeDomNavigationAxis, ec);
2149 m_currentNodeDomNavigationAxis = 0;
2152 selection->addRange(rangeRef.get());
2153 } else if (currentFocus()) {
2154 selection->setPosition(currentFocus(), 0, ec);
2155 } else if (m_cursorNode
2156 && CacheBuilder::validNode(m_mainFrame,
2157 m_mainFrame, m_cursorNode)) {
2158 PassRefPtr<Range> rangeRef =
2159 selection->frame()->document()->createRange();
2160 rangeRef->selectNode(reinterpret_cast<Node*>(m_cursorNode), ec);
2163 selection->addRange(rangeRef.get());
2165 selection->setPosition(body, 0, ec);
2171 // collapse the selection
2172 if (direction == DIRECTION_FORWARD)
2173 selection->collapseToEnd(ec);
2175 selection->collapseToStart(ec);
2179 // Make sure the anchor node is a text node since we are generating
2180 // the markup of the selection which includes the anchor, the focus,
2181 // and any crossed nodes. Forcing the condition that the selection
2182 // starts and ends on text nodes guarantees symmetric selection markup.
2183 // Also this way the text content, rather its container, is highlighted.
2184 Node* anchorNode = selection->anchorNode();
2185 if (anchorNode->isElementNode()) {
2186 // Collapsed selection while moving forward points to the
2187 // next unvisited node and while moving backward to the
2188 // last visited node.
2189 if (direction == DIRECTION_FORWARD)
2190 advanceAnchorNode(selection, direction, markup, false, ec);
2192 advanceAnchorNode(selection, direction, markup, true, ec);
2195 if (!markup.isEmpty())
2199 // If the selection is at the end of a non white space text move
2200 // it to the next visible text node with non white space content.
2201 // This is a workaround for the selection getting stuck.
2202 anchorNode = selection->anchorNode();
2203 if (anchorNode->isTextNode()) {
2204 if (direction == DIRECTION_FORWARD) {
2205 String suffix = anchorNode->textContent().substring(
2206 selection->anchorOffset(), caretMaxOffset(anchorNode));
2207 // If at the end of non white space text we advance the
2208 // anchor node to either an input element or non empty text.
2209 if (suffix.stripWhiteSpace().isEmpty()) {
2210 advanceAnchorNode(selection, direction, markup, true, ec);
2213 String prefix = anchorNode->textContent().substring(0,
2214 selection->anchorOffset());
2215 // If at the end of non white space text we advance the
2216 // anchor node to either an input element or non empty text.
2217 if (prefix.stripWhiteSpace().isEmpty()) {
2218 advanceAnchorNode(selection, direction, markup, true, ec);
2223 if (!markup.isEmpty())
2227 // extend the selection
2228 String directionStr;
2229 if (direction == DIRECTION_FORWARD)
2230 directionStr = "forward";
2232 directionStr = "backward";
2235 if (axis == AXIS_CHARACTER)
2236 axisStr = "character";
2237 else if (axis == AXIS_WORD)
2240 axisStr = "sentence";
2242 selection->modify("extend", directionStr, axisStr);
2244 // Make sure the focus node is a text node in order to have the
2245 // selection generate symmetric markup because the latter
2246 // includes all nodes crossed by the selection. Also this way
2247 // the text content, rather its container, is highlighted.
2248 Node* focusNode = selection->focusNode();
2249 if (focusNode->isElementNode()) {
2250 focusNode = getImplicitBoundaryNode(selection->focusNode(),
2251 selection->focusOffset(), direction);
2254 if (direction == DIRECTION_FORWARD) {
2255 focusNode = focusNode->traversePreviousSiblingPostOrder(body);
2256 if (focusNode && !isContentTextNode(focusNode)) {
2257 Node* textNode = traverseNextContentTextNode(focusNode,
2258 anchorNode, DIRECTION_BACKWARD);
2260 anchorNode = textNode;
2262 if (focusNode && isContentTextNode(focusNode)) {
2263 selection->extend(focusNode, caretMaxOffset(focusNode), ec);
2268 focusNode = focusNode->traverseNextSibling();
2269 if (focusNode && !isContentTextNode(focusNode)) {
2270 Node* textNode = traverseNextContentTextNode(focusNode,
2271 anchorNode, DIRECTION_FORWARD);
2273 anchorNode = textNode;
2275 if (anchorNode && isContentTextNode(anchorNode)) {
2276 selection->extend(focusNode, 0, ec);
2283 // Enforce that the selection does not cross anchor boundaries. This is
2284 // a workaround for the asymmetric behavior of WebKit while crossing
2286 anchorNode = getImplicitBoundaryNode(selection->anchorNode(),
2287 selection->anchorOffset(), direction);
2288 focusNode = getImplicitBoundaryNode(selection->focusNode(),
2289 selection->focusOffset(), direction);
2290 if (anchorNode && focusNode && anchorNode != focusNode) {
2291 Node* inputControl = getIntermediaryInputElement(anchorNode, focusNode,
2294 if (direction == DIRECTION_FORWARD) {
2295 if (isDescendantOf(inputControl, anchorNode)) {
2296 focusNode = inputControl;
2298 focusNode = inputControl->traversePreviousSiblingPostOrder(
2301 focusNode = inputControl;
2303 // We prefer a text node contained in the input element.
2304 if (!isContentTextNode(focusNode)) {
2305 Node* textNode = traverseNextContentTextNode(focusNode,
2306 anchorNode, DIRECTION_BACKWARD);
2308 focusNode = textNode;
2310 // If we found text in the input select it.
2311 // Otherwise, select the input element itself.
2312 if (isContentTextNode(focusNode)) {
2313 selection->extend(focusNode, caretMaxOffset(focusNode), ec);
2314 } else if (anchorNode != focusNode) {
2315 // Note that the focusNode always has parent and that
2316 // the offset can be one more that the index of the last
2317 // element - this is how WebKit selects such elements.
2318 selection->extend(focusNode->parentNode(),
2319 focusNode->nodeIndex() + 1, ec);
2324 if (isDescendantOf(inputControl, anchorNode)) {
2325 focusNode = inputControl;
2327 focusNode = inputControl->traverseNextSibling();
2329 focusNode = inputControl;
2331 // We prefer a text node contained in the input element.
2332 if (!isContentTextNode(focusNode)) {
2333 Node* textNode = traverseNextContentTextNode(focusNode,
2334 anchorNode, DIRECTION_FORWARD);
2336 focusNode = textNode;
2338 // If we found text in the input select it.
2339 // Otherwise, select the input element itself.
2340 if (isContentTextNode(focusNode)) {
2341 selection->extend(focusNode, caretMinOffset(focusNode), ec);
2342 } else if (anchorNode != focusNode) {
2343 // Note that the focusNode always has parent and that
2344 // the offset can be one more that the index of the last
2345 // element - this is how WebKit selects such elements.
2346 selection->extend(focusNode->parentNode(),
2347 focusNode->nodeIndex() + 1, ec);
2355 // make sure the selection is visible
2356 if (direction == DIRECTION_FORWARD)
2357 scrollNodeIntoView(m_mainFrame, selection->focusNode());
2359 scrollNodeIntoView(m_mainFrame, selection->anchorNode());
2361 // format markup for the visible content
2362 PassRefPtr<Range> range = selection->getRangeAt(0, ec);
2365 IntRect bounds = range->boundingBox();
2366 selectAt(bounds.center().x(), bounds.center().y());
2367 markup = formatMarkup(selection);
2368 LOGV("Selection markup: %s", markup.utf8().data());
2373 Node* WebViewCore::getImplicitBoundaryNode(Node* node, unsigned offset, int direction)
2375 if (node->offsetInCharacters())
2377 if (!node->hasChildNodes())
2379 if (offset < node->childNodeCount())
2380 return node->childNode(offset);
2382 if (direction == DIRECTION_FORWARD)
2383 return node->traverseNextSibling();
2385 return node->traversePreviousNodePostOrder(
2386 node->document()->body());
2389 Node* WebViewCore::getNextAnchorNode(Node* anchorNode, bool ignoreFirstNode, int direction)
2392 Node* currentNode = 0;
2393 if (direction == DIRECTION_FORWARD) {
2394 if (ignoreFirstNode)
2395 currentNode = anchorNode->traverseNextNode(body);
2397 currentNode = anchorNode;
2399 body = anchorNode->document()->body();
2400 if (ignoreFirstNode)
2401 currentNode = anchorNode->traversePreviousSiblingPostOrder(body);
2403 currentNode = anchorNode;
2405 while (currentNode) {
2406 if (isContentTextNode(currentNode)
2407 || isContentInputElement(currentNode))
2409 if (direction == DIRECTION_FORWARD)
2410 currentNode = currentNode->traverseNextNode();
2412 currentNode = currentNode->traversePreviousNodePostOrder(body);
2417 void WebViewCore::advanceAnchorNode(DOMSelection* selection, int direction,
2418 String& markup, bool ignoreFirstNode, ExceptionCode& ec)
2420 Node* anchorNode = getImplicitBoundaryNode(selection->anchorNode(),
2421 selection->anchorOffset(), direction);
2426 // If the anchor offset is invalid i.e. the anchor node has no
2427 // child with that index getImplicitAnchorNode returns the next
2428 // logical node in the current direction. In such a case our
2429 // position in the DOM tree was has already been advanced,
2430 // therefore we there is no need to do that again.
2431 if (selection->anchorNode()->isElementNode()) {
2432 unsigned anchorOffset = selection->anchorOffset();
2433 unsigned childNodeCount = selection->anchorNode()->childNodeCount();
2434 if (anchorOffset >= childNodeCount)
2435 ignoreFirstNode = false;
2437 // Find the next anchor node given our position in the DOM and
2438 // whether we want the current node to be considered as well.
2439 Node* nextAnchorNode = getNextAnchorNode(anchorNode, ignoreFirstNode,
2441 if (!nextAnchorNode) {
2445 if (nextAnchorNode->isElementNode()) {
2446 // If this is an input element tell the WebView thread
2447 // to set the cursor to that control.
2448 if (isContentInputElement(nextAnchorNode)) {
2449 IntRect bounds = nextAnchorNode->getRect();
2450 selectAt(bounds.center().x(), bounds.center().y());
2453 // Treat the text content of links as any other text but
2454 // for the rest input elements select the control itself.
2455 if (nextAnchorNode->hasTagName(WebCore::HTMLNames::aTag))
2456 textNode = traverseNextContentTextNode(nextAnchorNode,
2457 nextAnchorNode, direction);
2458 // We prefer to select the text content of the link if such,
2459 // otherwise just select the element itself.
2461 nextAnchorNode = textNode;
2463 if (direction == DIRECTION_FORWARD) {
2464 selection->setBaseAndExtent(nextAnchorNode,
2465 caretMinOffset(nextAnchorNode), nextAnchorNode,
2466 caretMaxOffset(nextAnchorNode), ec);
2468 selection->setBaseAndExtent(nextAnchorNode,
2469 caretMaxOffset(nextAnchorNode), nextAnchorNode,
2470 caretMinOffset(nextAnchorNode), ec);
2473 markup = formatMarkup(selection);
2474 // make sure the selection is visible
2475 scrollNodeIntoView(selection->frame(), nextAnchorNode);
2479 if (direction == DIRECTION_FORWARD)
2480 selection->setPosition(nextAnchorNode,
2481 caretMinOffset(nextAnchorNode), ec);
2483 selection->setPosition(nextAnchorNode,
2484 caretMaxOffset(nextAnchorNode), ec);
2487 bool WebViewCore::isContentInputElement(Node* node)
2489 return (isVisible(node)
2490 && (node->hasTagName(WebCore::HTMLNames::selectTag)
2491 || node->hasTagName(WebCore::HTMLNames::aTag)
2492 || node->hasTagName(WebCore::HTMLNames::inputTag)
2493 || node->hasTagName(WebCore::HTMLNames::buttonTag)));
2496 bool WebViewCore::isContentTextNode(Node* node)
2498 if (!node || !node->isTextNode())
2500 Text* textNode = static_cast<Text*>(node);
2501 return (isVisible(textNode) && textNode->length() > 0
2502 && !textNode->containsOnlyWhitespace());
2505 Text* WebViewCore::traverseNextContentTextNode(Node* fromNode, Node* toNode, int direction)
2507 Node* currentNode = fromNode;
2509 if (direction == DIRECTION_FORWARD)
2510 currentNode = currentNode->traverseNextNode(toNode);
2512 currentNode = currentNode->traversePreviousNodePostOrder(toNode);
2513 } while (currentNode && !isContentTextNode(currentNode));
2514 return static_cast<Text*>(currentNode);
2517 Node* WebViewCore::getIntermediaryInputElement(Node* fromNode, Node* toNode, int direction)
2519 if (fromNode == toNode)
2521 if (direction == DIRECTION_FORWARD) {
2522 Node* currentNode = fromNode;
2523 while (currentNode && currentNode != toNode) {
2524 if (isContentInputElement(currentNode))
2526 currentNode = currentNode->traverseNextNodePostOrder();
2528 currentNode = fromNode;
2529 while (currentNode && currentNode != toNode) {
2530 if (isContentInputElement(currentNode))
2532 currentNode = currentNode->traverseNextNode();
2535 Node* currentNode = fromNode->traversePreviousNode();
2536 while (currentNode && currentNode != toNode) {
2537 if (isContentInputElement(currentNode))
2539 currentNode = currentNode->traversePreviousNode();
2541 currentNode = fromNode->traversePreviousNodePostOrder();
2542 while (currentNode && currentNode != toNode) {
2543 if (isContentInputElement(currentNode))
2545 currentNode = currentNode->traversePreviousNodePostOrder();
2551 bool WebViewCore::isDescendantOf(Node* parent, Node* node)
2553 Node* currentNode = node;
2554 while (currentNode) {
2555 if (currentNode == parent) {
2558 currentNode = currentNode->parentNode();
2563 String WebViewCore::modifySelectionDomNavigationAxis(DOMSelection* selection, int direction, int axis)
2565 HTMLElement* body = m_mainFrame->document()->body();
2566 if (!m_currentNodeDomNavigationAxis && selection->focusNode()) {
2567 m_currentNodeDomNavigationAxis = selection->focusNode();
2569 if (m_currentNodeDomNavigationAxis->isTextNode())
2570 m_currentNodeDomNavigationAxis =
2571 m_currentNodeDomNavigationAxis->parentNode();
2573 if (!m_currentNodeDomNavigationAxis)
2574 m_currentNodeDomNavigationAxis = currentFocus();
2575 if (!m_currentNodeDomNavigationAxis
2576 || !CacheBuilder::validNode(m_mainFrame, m_mainFrame,
2577 m_currentNodeDomNavigationAxis))
2578 m_currentNodeDomNavigationAxis = body;
2579 Node* currentNode = m_currentNodeDomNavigationAxis;
2580 if (axis == AXIS_HEADING) {
2581 if (currentNode == body && direction == DIRECTION_BACKWARD)
2582 currentNode = currentNode->lastDescendant();
2584 if (direction == DIRECTION_FORWARD)
2585 currentNode = currentNode->traverseNextNode(body);
2587 currentNode = currentNode->traversePreviousNode(body);
2588 } while (currentNode && (currentNode->isTextNode()
2589 || !isVisible(currentNode) || !isHeading(currentNode)));
2590 } else if (axis == AXIS_PARENT_FIRST_CHILD) {
2591 if (direction == DIRECTION_FORWARD) {
2592 currentNode = currentNode->firstChild();
2593 while (currentNode && (currentNode->isTextNode()
2594 || !isVisible(currentNode)))
2595 currentNode = currentNode->nextSibling();
2598 if (currentNode == body)
2600 currentNode = currentNode->parentNode();
2601 } while (currentNode && (currentNode->isTextNode()
2602 || !isVisible(currentNode)));
2604 } else if (axis == AXIS_SIBLING) {
2606 if (direction == DIRECTION_FORWARD)
2607 currentNode = currentNode->nextSibling();
2609 if (currentNode == body)
2611 currentNode = currentNode->previousSibling();
2613 } while (currentNode && (currentNode->isTextNode()
2614 || !isVisible(currentNode)));
2615 } else if (axis == AXIS_DOCUMENT) {
2617 if (direction == DIRECTION_FORWARD)
2618 currentNode = currentNode->lastDescendant();
2620 LOGE("Invalid axis: %d", axis);
2624 m_currentNodeDomNavigationAxis = currentNode;
2625 scrollNodeIntoView(m_mainFrame, currentNode);
2626 String selectionString = createMarkup(currentNode);
2627 LOGV("Selection markup: %s", selectionString.utf8().data());
2628 return selectionString;
2633 bool WebViewCore::isHeading(Node* node)
2635 if (node->hasTagName(WebCore::HTMLNames::h1Tag)
2636 || node->hasTagName(WebCore::HTMLNames::h2Tag)
2637 || node->hasTagName(WebCore::HTMLNames::h3Tag)
2638 || node->hasTagName(WebCore::HTMLNames::h4Tag)
2639 || node->hasTagName(WebCore::HTMLNames::h5Tag)
2640 || node->hasTagName(WebCore::HTMLNames::h6Tag)) {
2644 if (node->isElementNode()) {
2645 Element* element = static_cast<Element*>(node);
2646 String roleAttribute =
2647 element->getAttribute(WebCore::HTMLNames::roleAttr).string();
2648 if (equalIgnoringCase(roleAttribute, "heading"))
2655 bool WebViewCore::isVisible(Node* node)
2657 // start off an element
2658 Element* element = 0;
2659 if (node->isElementNode())
2660 element = static_cast<Element*>(node);
2662 element = node->parentElement();
2664 if (!element->renderer()) {
2668 if (element->offsetHeight() == 0 || element->offsetWidth() == 0) {
2672 Node* body = m_mainFrame->document()->body();
2673 Node* currentNode = element;
2674 while (currentNode && currentNode != body) {
2675 RenderStyle* style = currentNode->computedStyle();
2677 (style->display() == NONE || style->visibility() == HIDDEN)) {
2680 currentNode = currentNode->parentNode();
2685 String WebViewCore::formatMarkup(DOMSelection* selection)
2687 ExceptionCode ec = 0;
2688 String markup = String();
2689 PassRefPtr<Range> wholeRange = selection->getRangeAt(0, ec);
2692 if (!wholeRange->startContainer() || !wholeRange->startContainer())
2694 // Since formatted markup contains invisible nodes it
2695 // is created from the concatenation of the visible fragments.
2696 Node* firstNode = wholeRange->firstNode();
2697 Node* pastLastNode = wholeRange->pastLastNode();
2698 Node* currentNode = firstNode;
2699 PassRefPtr<Range> currentRange;
2701 while (currentNode != pastLastNode) {
2702 Node* nextNode = currentNode->traverseNextNode();
2703 if (!isVisible(currentNode)) {
2705 markup = markup + currentRange->toHTML().utf8().data();
2709 if (!currentRange) {
2710 currentRange = selection->frame()->document()->createRange();
2713 if (currentNode == firstNode) {
2714 currentRange->setStart(wholeRange->startContainer(),
2715 wholeRange->startOffset(), ec);
2719 currentRange->setStart(currentNode->parentNode(),
2720 currentNode->nodeIndex(), ec);
2725 if (nextNode == pastLastNode) {
2726 currentRange->setEnd(wholeRange->endContainer(),
2727 wholeRange->endOffset(), ec);
2730 markup = markup + currentRange->toHTML().utf8().data();
2732 if (currentNode->offsetInCharacters())
2733 currentRange->setEnd(currentNode,
2734 currentNode->maxCharacterOffset(), ec);
2736 currentRange->setEnd(currentNode->parentNode(),
2737 currentNode->nodeIndex() + 1, ec);
2742 currentNode = nextNode;
2744 return markup.stripWhiteSpace();
2747 void WebViewCore::selectAt(int x, int y)
2749 JNIEnv* env = JSC::Bindings::getJNIEnv();
2750 env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_selectAt,
2752 checkException(env);
2755 void WebViewCore::deleteSelection(int start, int end, int textGeneration)
2757 setSelection(start, end);
2760 WebCore::Node* focus = currentFocus();
2763 // Prevent our editor client from passing a message to change the
2765 EditorClientAndroid* client = static_cast<EditorClientAndroid*>(
2766 m_mainFrame->editor()->client());
2767 client->setUiGeneratedSelectionChange(true);
2768 PlatformKeyboardEvent down(AKEYCODE_DEL, 0, 0, true, false, false, false);
2769 PlatformKeyboardEvent up(AKEYCODE_DEL, 0, 0, false, false, false, false);
2772 client->setUiGeneratedSelectionChange(false);
2773 m_textGeneration = textGeneration;
2774 m_shouldPaintCaret = true;
2777 void WebViewCore::replaceTextfieldText(int oldStart,
2778 int oldEnd, const WTF::String& replace, int start, int end,
2781 WebCore::Node* focus = currentFocus();
2784 setSelection(oldStart, oldEnd);
2785 // Prevent our editor client from passing a message to change the
2787 EditorClientAndroid* client = static_cast<EditorClientAndroid*>(
2788 m_mainFrame->editor()->client());
2789 client->setUiGeneratedSelectionChange(true);
2790 WebCore::TypingCommand::insertText(focus->document(), replace,
2792 client->setUiGeneratedSelectionChange(false);
2793 // setSelection calls revealSelection, so there is no need to do it here.
2794 setSelection(start, end);
2795 m_textGeneration = textGeneration;
2796 m_shouldPaintCaret = true;
2799 void WebViewCore::passToJs(int generation, const WTF::String& current,
2800 const PlatformKeyboardEvent& event)
2802 WebCore::Node* focus = currentFocus();
2804 DBG_NAV_LOG("!focus");
2808 WebCore::RenderObject* renderer = focus->renderer();
2809 if (!renderer || (!renderer->isTextField() && !renderer->isTextArea())) {
2810 DBG_NAV_LOGD("renderer==%p || not text", renderer);
2814 // Block text field updates during a key press.
2815 m_blockTextfieldUpdates = true;
2816 // Also prevent our editor client from passing a message to change the
2818 EditorClientAndroid* client = static_cast<EditorClientAndroid*>(
2819 m_mainFrame->editor()->client());
2820 client->setUiGeneratedSelectionChange(true);
2822 client->setUiGeneratedSelectionChange(false);
2823 m_blockTextfieldUpdates = false;
2824 m_textGeneration = generation;
2825 WebCore::RenderTextControl* renderText =
2826 static_cast<WebCore::RenderTextControl*>(renderer);
2827 WTF::String test = renderText->text();
2828 if (test != current) {
2829 // If the text changed during the key event, update the UI text field.
2830 updateTextfield(focus, false, test);
2832 DBG_NAV_LOG("test == current");
2834 // Now that the selection has settled down, send it.
2835 updateTextSelection();
2836 m_shouldPaintCaret = true;
2839 void WebViewCore::scrollFocusedTextInput(float xPercent, int y)
2841 WebCore::Node* focus = currentFocus();
2843 DBG_NAV_LOG("!focus");
2847 WebCore::RenderObject* renderer = focus->renderer();
2848 if (!renderer || (!renderer->isTextField() && !renderer->isTextArea())) {
2849 DBG_NAV_LOGD("renderer==%p || not text", renderer);
2853 WebCore::RenderTextControl* renderText =
2854 static_cast<WebCore::RenderTextControl*>(renderer);
2855 int x = (int) (xPercent * (renderText->scrollWidth() -
2856 renderText->clientWidth()));
2857 DBG_NAV_LOGD("x=%d y=%d xPercent=%g scrollW=%d clientW=%d", x, y,
2858 xPercent, renderText->scrollWidth(), renderText->clientWidth());
2859 renderText->setScrollLeft(x);
2860 renderText->setScrollTop(y);
2863 void WebViewCore::setFocusControllerActive(bool active)
2865 m_mainFrame->page()->focusController()->setActive(active);
2868 void WebViewCore::saveDocumentState(WebCore::Frame* frame)
2870 if (!CacheBuilder::validNode(m_mainFrame, frame, 0))
2871 frame = m_mainFrame;
2872 WebCore::HistoryItem *item = frame->loader()->history()->currentItem();
2874 // item can be null when there is no offical URL for the current page. This happens
2875 // when the content is loaded using with WebCoreFrameBridge::LoadData() and there
2876 // is no failing URL (common case is when content is loaded using data: scheme)
2878 item->setDocumentState(frame->document()->formElementsState());
2882 // Create an array of java Strings.
2883 static jobjectArray makeLabelArray(JNIEnv* env, const uint16_t** labels, size_t count)
2885 jclass stringClass = env->FindClass("java/lang/String");
2886 LOG_ASSERT(stringClass, "Could not find java/lang/String");
2887 jobjectArray array = env->NewObjectArray(count, stringClass, 0);
2888 LOG_ASSERT(array, "Could not create new string array");
2890 for (size_t i = 0; i < count; i++) {
2891 jobject newString = env->NewString(&labels[i][1], labels[i][0]);
2892 env->SetObjectArrayElement(array, i, newString);
2893 env->DeleteLocalRef(newString);
2894 checkException(env);
2896 env->DeleteLocalRef(stringClass);
2900 void WebViewCore::openFileChooser(PassRefPtr<WebCore::FileChooser> chooser) {
2903 JNIEnv* env = JSC::Bindings::getJNIEnv();
2905 WTF::String acceptType = chooser->acceptTypes();
2906 jstring jAcceptType = wtfStringToJstring(env, acceptType, true);
2907 jstring jName = (jstring) env->CallObjectMethod(
2908 m_javaGlue->object(env).get(), m_javaGlue->m_openFileChooser, jAcceptType);
2909 checkException(env);
2910 env->DeleteLocalRef(jAcceptType);
2912 const UChar* string = static_cast<const UChar*>(env->GetStringChars(jName, NULL));
2917 WTF::String webcoreString = jstringToWtfString(env, jName);
2918 env->ReleaseStringChars(jName, string);
2920 if (webcoreString.length())
2921 chooser->chooseFile(webcoreString);
2924 void WebViewCore::listBoxRequest(WebCoreReply* reply, const uint16_t** labels, size_t count, const int enabled[], size_t enabledCount,
2925 bool multiple, const int selected[], size_t selectedCountOrSelection)
2927 // If m_popupReply is not null, then we already have a list showing.
2928 if (m_popupReply != 0)
2931 LOG_ASSERT(m_javaGlue->m_obj, "No java widget associated with this view!");
2933 // Create an array of java Strings for the drop down.
2934 JNIEnv* env = JSC::Bindings::getJNIEnv();
2935 jobjectArray labelArray = makeLabelArray(env, labels, count);
2937 // Create an array determining whether each item is enabled.
2938 jintArray enabledArray = env->NewIntArray(enabledCount);
2939 checkException(env);
2940 jint* ptrArray = env->GetIntArrayElements(enabledArray, 0);
2941 checkException(env);
2942 for (size_t i = 0; i < enabledCount; i++) {
2943 ptrArray[i] = enabled[i];
2945 env->ReleaseIntArrayElements(enabledArray, ptrArray, 0);
2946 checkException(env);
2949 // Pass up an array representing which items are selected.
2950 jintArray selectedArray = env->NewIntArray(selectedCountOrSelection);
2951 checkException(env);
2952 jint* selArray = env->GetIntArrayElements(selectedArray, 0);
2953 checkException(env);
2954 for (size_t i = 0; i < selectedCountOrSelection; i++) {
2955 selArray[i] = selected[i];
2957 env->ReleaseIntArrayElements(selectedArray, selArray, 0);
2959 env->CallVoidMethod(m_javaGlue->object(env).get(),
2960 m_javaGlue->m_requestListBox, labelArray, enabledArray,
2962 env->DeleteLocalRef(selectedArray);
2964 // Pass up the single selection.
2965 env->CallVoidMethod(m_javaGlue->object(env).get(),
2966 m_javaGlue->m_requestSingleListBox, labelArray, enabledArray,
2967 selectedCountOrSelection);
2970 env->DeleteLocalRef(labelArray);
2971 env->DeleteLocalRef(enabledArray);
2972 checkException(env);
2975 m_popupReply = reply;
2978 bool WebViewCore::key(const PlatformKeyboardEvent& event)
2980 WebCore::EventHandler* eventHandler;
2981 WebCore::Node* focusNode = currentFocus();
2982 DBG_NAV_LOGD("keyCode=%s unichar=%d focusNode=%p",
2983 event.keyIdentifier().utf8().data(), event.unichar(), focusNode);
2985 WebCore::Frame* frame = focusNode->document()->frame();
2986 WebFrame* webFrame = WebFrame::getWebFrame(frame);
2987 eventHandler = frame->eventHandler();
2988 VisibleSelection old = frame->selection()->selection();
2989 bool handled = eventHandler->keyEvent(event);
2990 if (isContentEditable(focusNode)) {
2991 // keyEvent will return true even if the contentEditable did not
2992 // change its selection. In the case that it does not, we want to
2993 // return false so that the key will be sent back to our navigation
2995 handled |= frame->selection()->selection() != old;
2999 eventHandler = m_mainFrame->eventHandler();
3001 return eventHandler->keyEvent(event);
3004 // For when the user clicks the trackball, presses dpad center, or types into an
3005 // unfocused textfield. In the latter case, 'fake' will be true
3006 void WebViewCore::click(WebCore::Frame* frame, WebCore::Node* node, bool fake) {
3008 WebCore::IntPoint pt = m_mousePos;
3009 pt.move(m_scrollOffsetX, m_scrollOffsetY);
3010 WebCore::HitTestResult hitTestResult = m_mainFrame->eventHandler()->
3011 hitTestResultAtPoint(pt, false);
3012 node = hitTestResult.innerNode();
3013 frame = node->document()->frame();
3014 DBG_NAV_LOGD("m_mousePos=(%d,%d) m_scrollOffset=(%d,%d) pt=(%d,%d)"
3015 " node=%p", m_mousePos.x(), m_mousePos.y(),
3016 m_scrollOffsetX, m_scrollOffsetY, pt.x(), pt.y(), node);
3019 EditorClientAndroid* client
3020 = static_cast<EditorClientAndroid*>(
3021 m_mainFrame->editor()->client());
3022 client->setShouldChangeSelectedRange(false);
3023 handleMouseClick(frame, node, fake);
3024 client->setShouldChangeSelectedRange(true);
3028 #if USE(ACCELERATED_COMPOSITING)
3029 GraphicsLayerAndroid* WebViewCore::graphicsRootLayer() const
3031 RenderView* contentRenderer = m_mainFrame->contentRenderer();
3032 if (!contentRenderer)
3034 return static_cast<GraphicsLayerAndroid*>(
3035 contentRenderer->compositor()->rootPlatformLayer());
3039 bool WebViewCore::handleTouchEvent(int action, Vector<int>& ids, Vector<IntPoint>& points, int actionIndex, int metaState)
3041 bool preventDefault = false;
3043 #if USE(ACCELERATED_COMPOSITING)
3044 GraphicsLayerAndroid* rootLayer = graphicsRootLayer();
3046 rootLayer->pauseDisplay(true);
3049 #if ENABLE(TOUCH_EVENTS) // Android
3050 #define MOTION_EVENT_ACTION_POINTER_DOWN 5
3051 #define MOTION_EVENT_ACTION_POINTER_UP 6
3053 WebCore::TouchEventType type = WebCore::TouchStart;
3054 WebCore::PlatformTouchPoint::State defaultTouchState;
3055 Vector<WebCore::PlatformTouchPoint::State> touchStates(points.size());
3058 case 0: // MotionEvent.ACTION_DOWN
3059 type = WebCore::TouchStart;
3060 defaultTouchState = WebCore::PlatformTouchPoint::TouchPressed;
3062 case 1: // MotionEvent.ACTION_UP
3063 type = WebCore::TouchEnd;
3064 defaultTouchState = WebCore::PlatformTouchPoint::TouchReleased;
3066 case 2: // MotionEvent.ACTION_MOVE
3067 type = WebCore::TouchMove;
3068 defaultTouchState = WebCore::PlatformTouchPoint::TouchMoved;
3070 case 3: // MotionEvent.ACTION_CANCEL
3071 type = WebCore::TouchCancel;
3072 defaultTouchState = WebCore::PlatformTouchPoint::TouchCancelled;
3074 case 5: // MotionEvent.ACTION_POINTER_DOWN
3075 type = WebCore::TouchStart;
3076 defaultTouchState = WebCore::PlatformTouchPoint::TouchStationary;
3078 case 6: // MotionEvent.ACTION_POINTER_UP
3079 type = WebCore::TouchEnd;
3080 defaultTouchState = WebCore::PlatformTouchPoint::TouchStationary;
3082 case 0x100: // WebViewCore.ACTION_LONGPRESS
3083 type = WebCore::TouchLongPress;
3084 defaultTouchState = WebCore::PlatformTouchPoint::TouchPressed;
3086 case 0x200: // WebViewCore.ACTION_DOUBLETAP
3087 type = WebCore::TouchDoubleTap;
3088 defaultTouchState = WebCore::PlatformTouchPoint::TouchPressed;
3091 // We do not support other kinds of touch event inside WebCore
3093 LOGW("Java passed a touch event type that we do not support in WebCore: %d", action);
3097 for (int c = 0; c < static_cast<int>(points.size()); c++) {
3098 points[c].setX(points[c].x() - m_scrollOffsetX);
3099 points[c].setY(points[c].y() - m_scrollOffsetY);
3101 // Setting the touch state for each point.
3102 // Note: actionIndex will be 0 for all actions that are not ACTION_POINTER_DOWN/UP.
3103 if (action == MOTION_EVENT_ACTION_POINTER_DOWN && c == actionIndex) {
3104 touchStates[c] = WebCore::PlatformTouchPoint::TouchPressed;
3105 } else if (action == MOTION_EVENT_ACTION_POINTER_UP && c == actionIndex) {
3106 touchStates[c] = WebCore::PlatformTouchPoint::TouchReleased;
3108 touchStates[c] = defaultTouchState;
3112 WebCore::PlatformTouchEvent te(ids, points, type, touchStates, metaState);
3113 preventDefault = m_mainFrame->eventHandler()->handleTouchEvent(te);
3116 #if USE(ACCELERATED_COMPOSITING)
3118 rootLayer->pauseDisplay(false);
3120 return preventDefault;
3123 void WebViewCore::touchUp(int touchGeneration,
3124 WebCore::Frame* frame, WebCore::Node* node, int x, int y)
3126 if (touchGeneration == 0) {
3127 // m_mousePos should be set in getTouchHighlightRects()
3128 WebCore::HitTestResult hitTestResult = m_mainFrame->eventHandler()->hitTestResultAtPoint(m_mousePos, false);
3129 node = hitTestResult.innerNode();
3131 frame = node->document()->frame();
3134 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);
3136 if (m_touchGeneration > touchGeneration) {
3137 DBG_NAV_LOGD("m_touchGeneration=%d > touchGeneration=%d"
3138 " x=%d y=%d", m_touchGeneration, touchGeneration, x, y);
3139 return; // short circuit if a newer touch has been generated
3141 // This moves m_mousePos to the correct place, and handleMouseClick uses
3142 // m_mousePos to determine where the click happens.
3143 moveMouse(frame, x, y);
3144 m_lastGeneration = touchGeneration;
3146 if (frame && CacheBuilder::validNode(m_mainFrame, frame, 0)) {
3147 frame->loader()->resetMultipleFormSubmissionProtection();
3149 DBG_NAV_LOGD("touchGeneration=%d handleMouseClick frame=%p node=%p"
3150 " x=%d y=%d", touchGeneration, frame, node, x, y);
3151 handleMouseClick(frame, node, false);
3154 // Check for the "x-webkit-soft-keyboard" attribute. If it is there and
3155 // set to hidden, do not show the soft keyboard. Node passed as a parameter
3156 // must not be null.
3157 static bool shouldSuppressKeyboard(const WebCore::Node* node) {
3158 LOG_ASSERT(node, "node passed to shouldSuppressKeyboard cannot be null");
3159 const NamedNodeMap* attributes = node->attributes();
3160 if (!attributes) return false;
3161 size_t length = attributes->length();
3162 for (size_t i = 0; i < length; i++) {
3163 const Attribute* a = attributes->attributeItem(i);
3164 if (a->localName() == "x-webkit-soft-keyboard" && a->value() == "hidden")
3170 // Common code for both clicking with the trackball and touchUp
3171 // Also used when typing into a non-focused textfield to give the textfield focus,
3172 // in which case, 'fake' is set to true
3173 bool WebViewCore::handleMouseClick(WebCore::Frame* framePtr, WebCore::Node* nodePtr, bool fake)
3175 bool valid = !framePtr || CacheBuilder::validNode(m_mainFrame, framePtr, nodePtr);
3176 WebFrame* webFrame = WebFrame::getWebFrame(m_mainFrame);
3177 if (valid && nodePtr) {
3178 // Need to special case area tags because an image map could have an area element in the middle
3179 // so when attempting to get the default, the point chosen would be follow the wrong link.
3180 if (nodePtr->hasTagName(WebCore::HTMLNames::areaTag)) {
3181 webFrame->setUserInitiatedAction(true);
3182 nodePtr->dispatchSimulatedClick(0, true, true);
3183 webFrame->setUserInitiatedAction(false);
3184 DBG_NAV_LOG("area");
3188 if (!valid || !framePtr)
3189 framePtr = m_mainFrame;
3190 webFrame->setUserInitiatedAction(true);
3191 WebCore::PlatformMouseEvent mouseDown(m_mousePos, m_mousePos, WebCore::LeftButton,
3192 WebCore::MouseEventPressed, 1, false, false, false, false,
3193 WTF::currentTime());
3194 // ignore the return from as it will return true if the hit point can trigger selection change
3195 framePtr->eventHandler()->handleMousePressEvent(mouseDown);
3196 WebCore::PlatformMouseEvent mouseUp(m_mousePos, m_mousePos, WebCore::LeftButton,
3197 WebCore::MouseEventReleased, 1, false, false, false, false,
3198 WTF::currentTime());
3199 bool handled = framePtr->eventHandler()->handleMouseReleaseEvent(mouseUp);
3200 webFrame->setUserInitiatedAction(false);
3202 // If the user clicked on a textfield, make the focusController active
3203 // so we show the blinking cursor.
3204 WebCore::Node* focusNode = currentFocus();
3205 DBG_NAV_LOGD("m_mousePos={%d,%d} focusNode=%p handled=%s", m_mousePos.x(),
3206 m_mousePos.y(), focusNode, handled ? "true" : "false");
3208 WebCore::RenderObject* renderer = focusNode->renderer();
3209 if (renderer && (renderer->isTextField() || renderer->isTextArea())) {
3210 bool ime = !shouldSuppressKeyboard(focusNode)
3211 && !(static_cast<WebCore::HTMLInputElement*>(focusNode))->readOnly();
3213 #if ENABLE(WEB_AUTOFILL)
3214 if (renderer->isTextField()) {
3215 EditorClientAndroid* editorC = static_cast<EditorClientAndroid*>(framePtr->page()->editorClient());
3216 WebAutoFill* autoFill = editorC->getAutoFill();
3217 autoFill->formFieldFocused(static_cast<HTMLFormControlElement*>(focusNode));
3221 RenderTextControl* rtc
3222 = static_cast<RenderTextControl*> (renderer);
3223 requestKeyboardWithSelection(focusNode, rtc->selectionStart(),
3224 rtc->selectionEnd());
3227 requestKeyboard(false);
3230 // If the selection is contentEditable, show the keyboard so the
3231 // user can type. Otherwise hide the keyboard because no text
3233 if (isContentEditable(focusNode)) {
3234 requestKeyboard(true);
3235 } else if (!nodeIsPlugin(focusNode)) {
3240 // There is no focusNode, so the keyboard is not needed.
3246 void WebViewCore::popupReply(int index)
3249 m_popupReply->replyInt(index);
3250 Release(m_popupReply);
3255 void WebViewCore::popupReply(const int* array, int count)
3258 m_popupReply->replyIntArray(array, count);
3259 Release(m_popupReply);
3264 void WebViewCore::formDidBlur(const WebCore::Node* node)
3266 // If the blur is on a text input, keep track of the node so we can
3267 // hide the soft keyboard when the new focus is set, if it is not a
3269 if (isTextInput(node))
3270 m_blurringNodePointer = reinterpret_cast<int>(node);
3273 void WebViewCore::focusNodeChanged(const WebCore::Node* newFocus)
3275 if (isTextInput(newFocus))
3276 m_shouldPaintCaret = true;
3277 else if (m_blurringNodePointer) {
3278 JNIEnv* env = JSC::Bindings::getJNIEnv();
3279 env->CallVoidMethod(m_javaGlue->object(env).get(),
3280 m_javaGlue->m_formDidBlur, m_blurringNodePointer);
3281 checkException(env);
3282 m_blurringNodePointer = 0;
3286 void WebViewCore::addMessageToConsole(const WTF::String& message, unsigned int lineNumber, const WTF::String& sourceID, int msgLevel) {
3287 JNIEnv* env = JSC::Bindings::getJNIEnv();
3288 jstring jMessageStr = wtfStringToJstring(env, message);
3289 jstring jSourceIDStr = wtfStringToJstring(env, sourceID);
3290 env->CallVoidMethod(m_javaGlue->object(env).get(),
3291 m_javaGlue->m_addMessageToConsole, jMessageStr, lineNumber,
3292 jSourceIDStr, msgLevel);
3293 env->DeleteLocalRef(jMessageStr);
3294 env->DeleteLocalRef(jSourceIDStr);
3295 checkException(env);
3298 void WebViewCore::jsAlert(const WTF::String& url, const WTF::String& text)
3300 JNIEnv* env = JSC::Bindings::getJNIEnv();
3301 jstring jInputStr = wtfStringToJstring(env, text);
3302 jstring jUrlStr = wtfStringToJstring(env, url);
3303 env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_jsAlert, jUrlStr, jInputStr);
3304 env->DeleteLocalRef(jInputStr);
3305 env->DeleteLocalRef(jUrlStr);
3306 checkException(env);
3309 void WebViewCore::exceededDatabaseQuota(const WTF::String& url, const WTF::String& databaseIdentifier, const unsigned long long currentQuota, unsigned long long estimatedSize)
3311 #if ENABLE(DATABASE)
3312 JNIEnv* env = JSC::Bindings::getJNIEnv();
3313 jstring jDatabaseIdentifierStr = wtfStringToJstring(env, databaseIdentifier);
3314 jstring jUrlStr = wtfStringToJstring(env, url);
3315 env->CallVoidMethod(m_javaGlue->object(env).get(),
3316 m_javaGlue->m_exceededDatabaseQuota, jUrlStr,
3317 jDatabaseIdentifierStr, currentQuota, estimatedSize);
3318 env->DeleteLocalRef(jDatabaseIdentifierStr);
3319 env->DeleteLocalRef(jUrlStr);
3320 checkException(env);
3324 void WebViewCore::reachedMaxAppCacheSize(const unsigned long long spaceNeeded)
3326 #if ENABLE(OFFLINE_WEB_APPLICATIONS)
3327 JNIEnv* env = JSC::Bindings::getJNIEnv();
3328 env->CallVoidMethod(m_javaGlue->object(env).get(),
3329 m_javaGlue->m_reachedMaxAppCacheSize, spaceNeeded);
3330 checkException(env);
3334 void WebViewCore::populateVisitedLinks(WebCore::PageGroup* group)
3336 m_groupForVisitedLinks = group;
3337 JNIEnv* env = JSC::Bindings::getJNIEnv();
3338 env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_populateVisitedLinks);
3339 checkException(env);
3342 void WebViewCore::geolocationPermissionsShowPrompt(const WTF::String& origin)
3344 JNIEnv* env = JSC::Bindings::getJNIEnv();
3345 jstring originString = wtfStringToJstring(env, origin);
3346 env->CallVoidMethod(m_javaGlue->object(env).get(),
3347 m_javaGlue->m_geolocationPermissionsShowPrompt,
3349 env->DeleteLocalRef(originString);
3350 checkException(env);
3353 void WebViewCore::geolocationPermissionsHidePrompt()
3355 JNIEnv* env = JSC::Bindings::getJNIEnv();
3356 env->CallVoidMethod(m_javaGlue->object(env).get(),
3357 m_javaGlue->m_geolocationPermissionsHidePrompt);
3358 checkException(env);
3361 jobject WebViewCore::getDeviceMotionService()
3363 JNIEnv* env = JSC::Bindings::getJNIEnv();
3364 jobject object = env->CallObjectMethod(m_javaGlue->object(env).get(),
3365 m_javaGlue->m_getDeviceMotionService);
3366 checkException(env);
3370 jobject WebViewCore::getDeviceOrientationService()
3372 JNIEnv* env = JSC::Bindings::getJNIEnv();
3373 jobject object = env->CallObjectMethod(m_javaGlue->object(env).get(),
3374 m_javaGlue->m_getDeviceOrientationService);
3375 checkException(env);
3379 bool WebViewCore::jsConfirm(const WTF::String& url, const WTF::String& text)
3381 JNIEnv* env = JSC::Bindings::getJNIEnv();
3382 jstring jInputStr = wtfStringToJstring(env, text);
3383 jstring jUrlStr = wtfStringToJstring(env, url);
3384 jboolean result = env->CallBooleanMethod(m_javaGlue->object(env).get(), m_javaGlue->m_jsConfirm, jUrlStr, jInputStr);
3385 env->DeleteLocalRef(jInputStr);
3386 env->DeleteLocalRef(jUrlStr);
3387 checkException(env);
3391 bool WebViewCore::jsPrompt(const WTF::String& url, const WTF::String& text, const WTF::String& defaultValue, WTF::String& result)
3393 JNIEnv* env = JSC::Bindings::getJNIEnv();
3394 jstring jUrlStr = wtfStringToJstring(env, url);
3395 jstring jInputStr = wtfStringToJstring(env, text);
3396 jstring jDefaultStr = wtfStringToJstring(env, defaultValue);
3397 jstring returnVal = static_cast<jstring>(env->CallObjectMethod(m_javaGlue->object(env).get(), m_javaGlue->m_jsPrompt, jUrlStr, jInputStr, jDefaultStr));
3398 env->DeleteLocalRef(jUrlStr);
3399 env->DeleteLocalRef(jInputStr);
3400 env->DeleteLocalRef(jDefaultStr);
3401 checkException(env);
3403 // If returnVal is null, it means that the user cancelled the dialog.
3407 result = jstringToWtfString(env, returnVal);
3408 env->DeleteLocalRef(returnVal);
3412 bool WebViewCore::jsUnload(const WTF::String& url, const WTF::String& message)
3414 JNIEnv* env = JSC::Bindings::getJNIEnv();
3415 jstring jInputStr = wtfStringToJstring(env, message);
3416 jstring jUrlStr = wtfStringToJstring(env, url);
3417 jboolean result = env->CallBooleanMethod(m_javaGlue->object(env).get(), m_javaGlue->m_jsUnload, jUrlStr, jInputStr);
3418 env->DeleteLocalRef(jInputStr);
3419 env->DeleteLocalRef(jUrlStr);
3420 checkException(env);
3424 bool WebViewCore::jsInterrupt()
3426 JNIEnv* env = JSC::Bindings::getJNIEnv();
3427 jboolean result = env->CallBooleanMethod(m_javaGlue->object(env).get(), m_javaGlue->m_jsInterrupt);
3428 checkException(env);
3433 WebViewCore::getJavaObject()
3435 return m_javaGlue->object(JSC::Bindings::getJNIEnv());
3439 WebViewCore::getWebViewJavaObject()
3441 JNIEnv* env = JSC::Bindings::getJNIEnv();
3442 return env->GetObjectField(m_javaGlue->object(env).get(), gWebViewCoreFields.m_webView);
3445 void WebViewCore::updateTextSelection() {
3446 WebCore::Node* focusNode = currentFocus();
3449 RenderObject* renderer = focusNode->renderer();
3450 if (!renderer || (!renderer->isTextArea() && !renderer->isTextField()))
3452 RenderTextControl* rtc = static_cast<RenderTextControl*>(renderer);
3453 JNIEnv* env = JSC::Bindings::getJNIEnv();
3454 env->CallVoidMethod(m_javaGlue->object(env).get(),
3455 m_javaGlue->m_updateTextSelection, reinterpret_cast<int>(focusNode),
3456 rtc->selectionStart(), rtc->selectionEnd(), m_textGeneration);
3457 checkException(env);
3460 void WebViewCore::updateTextfield(WebCore::Node* ptr, bool changeToPassword,
3461 const WTF::String& text)
3463 if (m_blockTextfieldUpdates)
3465 JNIEnv* env = JSC::Bindings::getJNIEnv();
3466 if (changeToPassword) {
3467 env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_updateTextfield,
3468 (int) ptr, true, 0, m_textGeneration);
3469 checkException(env);
3472 jstring string = wtfStringToJstring(env, text);
3473 env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_updateTextfield,
3474 (int) ptr, false, string, m_textGeneration);
3475 env->DeleteLocalRef(string);
3476 checkException(env);
3479 void WebViewCore::clearTextEntry()
3481 JNIEnv* env = JSC::Bindings::getJNIEnv();
3482 env->CallVoidMethod(m_javaGlue->object(env).get(),
3483 m_javaGlue->m_clearTextEntry);
3486 void WebViewCore::setBackgroundColor(SkColor c)
3488 WebCore::FrameView* view = m_mainFrame->view();
3492 // need (int) cast to find the right constructor
3493 WebCore::Color bcolor((int)SkColorGetR(c), (int)SkColorGetG(c),
3494 (int)SkColorGetB(c), (int)SkColorGetA(c));
3495 view->setBaseBackgroundColor(bcolor);
3497 // Background color of 0 indicates we want a transparent background
3499 view->setTransparent(true);
3502 jclass WebViewCore::getPluginClass(const WTF::String& libName, const char* className)
3504 JNIEnv* env = JSC::Bindings::getJNIEnv();
3506 jstring libString = wtfStringToJstring(env, libName);
3507 jstring classString = env->NewStringUTF(className);
3508 jobject pluginClass = env->CallObjectMethod(m_javaGlue->object(env).get(),
3509 m_javaGlue->m_getPluginClass,
3510 libString, classString);
3511 checkException(env);
3513 // cleanup unneeded local JNI references
3514 env->DeleteLocalRef(libString);
3515 env->DeleteLocalRef(classString);
3517 if (pluginClass != NULL) {
3518 return static_cast<jclass>(pluginClass);
3524 void WebViewCore::showFullScreenPlugin(jobject childView, NPP npp)
3526 JNIEnv* env = JSC::Bindings::getJNIEnv();
3527 AutoJObject obj = m_javaGlue->object(env);
3529 env->CallVoidMethod(obj.get(),
3530 m_javaGlue->m_showFullScreenPlugin, childView, (int)npp);
3531 checkException(env);
3534 void WebViewCore::hideFullScreenPlugin()
3536 JNIEnv* env = JSC::Bindings::getJNIEnv();
3537 env->CallVoidMethod(m_javaGlue->object(env).get(),
3538 m_javaGlue->m_hideFullScreenPlugin);
3539 checkException(env);
3542 jobject WebViewCore::createSurface(jobject view)
3544 JNIEnv* env = JSC::Bindings::getJNIEnv();
3545 jobject result = env->CallObjectMethod(m_javaGlue->object(env).get(),
3546 m_javaGlue->m_createSurface, view);
3547 checkException(env);
3551 jobject WebViewCore::addSurface(jobject view, int x, int y, int width, int height)
3553 JNIEnv* env = JSC::Bindings::getJNIEnv();
3554 jobject result = env->CallObjectMethod(m_javaGlue->object(env).get(),
3555 m_javaGlue->m_addSurface,
3556 view, x, y, width, height);
3557 checkException(env);
3561 void WebViewCore::updateSurface(jobject childView, int x, int y, int width, int height)
3563 JNIEnv* env = JSC::Bindings::getJNIEnv();
3564 env->CallVoidMethod(m_javaGlue->object(env).get(),
3565 m_javaGlue->m_updateSurface, childView,
3566 x, y, width, height);
3567 checkException(env);
3570 void WebViewCore::destroySurface(jobject childView)
3572 JNIEnv* env = JSC::Bindings::getJNIEnv();
3573 env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_destroySurface, childView);
3574 checkException(env);
3577 jobject WebViewCore::getContext()
3579 JNIEnv* env = JSC::Bindings::getJNIEnv();
3580 AutoJObject obj = m_javaGlue->object(env);
3582 jobject result = env->CallObjectMethod(obj.get(), m_javaGlue->m_getContext);
3583 checkException(env);
3587 void WebViewCore::keepScreenOn(bool screenOn) {
3588 if ((screenOn && m_screenOnCounter == 0) || (!screenOn && m_screenOnCounter == 1)) {
3589 JNIEnv* env = JSC::Bindings::getJNIEnv();
3590 env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_keepScreenOn, screenOn);
3591 checkException(env);
3594 // update the counter
3596 m_screenOnCounter++;
3597 else if (m_screenOnCounter > 0)
3598 m_screenOnCounter--;
3601 bool WebViewCore::validNodeAndBounds(Frame* frame, Node* node,
3602 const IntRect& originalAbsoluteBounds)
3604 bool valid = CacheBuilder::validNode(m_mainFrame, frame, node);
3607 RenderObject* renderer = node->renderer();
3610 IntRect absBounds = node->hasTagName(HTMLNames::areaTag)
3611 ? CacheBuilder::getAreaRect(static_cast<HTMLAreaElement*>(node))
3612 : renderer->absoluteBoundingBoxRect();
3613 return absBounds == originalAbsoluteBounds;
3616 void WebViewCore::showRect(int left, int top, int width, int height,
3617 int contentWidth, int contentHeight, float xPercentInDoc,
3618 float xPercentInView, float yPercentInDoc, float yPercentInView)
3620 JNIEnv* env = JSC::Bindings::getJNIEnv();
3621 env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_showRect,
3622 left, top, width, height, contentWidth, contentHeight,
3623 xPercentInDoc, xPercentInView, yPercentInDoc, yPercentInView);
3624 checkException(env);
3627 void WebViewCore::centerFitRect(int x, int y, int width, int height)
3629 JNIEnv* env = JSC::Bindings::getJNIEnv();
3630 env->CallVoidMethod(m_javaGlue->object(env).get(),
3631 m_javaGlue->m_centerFitRect, x, y, width, height);
3632 checkException(env);
3636 void WebViewCore::setScrollbarModes(ScrollbarMode horizontalMode, ScrollbarMode verticalMode)
3638 JNIEnv* env = JSC::Bindings::getJNIEnv();
3639 env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_setScrollbarModes,
3640 horizontalMode, verticalMode);
3641 checkException(env);
3644 void WebViewCore::notifyWebAppCanBeInstalled()
3646 JNIEnv* env = JSC::Bindings::getJNIEnv();
3647 env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_setInstallableWebApp);
3648 checkException(env);
3652 void WebViewCore::enterFullscreenForVideoLayer(int layerId, const WTF::String& url)
3654 JNIEnv* env = JSC::Bindings::getJNIEnv();
3655 jstring jUrlStr = wtfStringToJstring(env, url);
3656 env->CallVoidMethod(m_javaGlue->object(env).get(),
3657 m_javaGlue->m_enterFullscreenForVideoLayer, layerId, jUrlStr);
3658 checkException(env);
3662 void WebViewCore::setWebTextViewAutoFillable(int queryId, const string16& previewSummary)
3664 #if ENABLE(WEB_AUTOFILL)
3665 JNIEnv* env = JSC::Bindings::getJNIEnv();
3666 jstring preview = env->NewString(previewSummary.data(), previewSummary.length());
3667 env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_setWebTextViewAutoFillable, queryId, preview);
3668 env->DeleteLocalRef(preview);
3672 bool WebViewCore::drawIsPaused() const
3674 JNIEnv* env = JSC::Bindings::getJNIEnv();
3675 return env->GetBooleanField(m_javaGlue->object(env).get(),
3676 gWebViewCoreFields.m_drawIsPaused);
3679 #if USE(CHROME_NETWORK_STACK)
3680 void WebViewCore::setWebRequestContextUserAgent()
3682 // We cannot create a WebRequestContext, because we might not know it this is a private tab or not yet
3683 if (m_webRequestContext)
3684 m_webRequestContext->setUserAgent(WebFrame::getWebFrame(m_mainFrame)->userAgentForURL(0)); // URL not used
3687 void WebViewCore::setWebRequestContextCacheMode(int cacheMode)
3689 m_cacheMode = cacheMode;
3690 // We cannot create a WebRequestContext, because we might not know it this is a private tab or not yet
3691 if (!m_webRequestContext)
3694 m_webRequestContext->setCacheMode(cacheMode);
3697 WebRequestContext* WebViewCore::webRequestContext()
3699 if (!m_webRequestContext) {
3700 Settings* settings = mainFrame()->settings();
3701 m_webRequestContext = new WebRequestContext(settings && settings->privateBrowsingEnabled());
3702 setWebRequestContextUserAgent();
3703 setWebRequestContextCacheMode(m_cacheMode);
3705 return m_webRequestContext.get();
3709 void WebViewCore::scrollRenderLayer(int layer, const SkRect& rect)
3711 #if USE(ACCELERATED_COMPOSITING)
3712 GraphicsLayerAndroid* root = graphicsRootLayer();
3716 LayerAndroid* layerAndroid = root->platformLayer();
3720 LayerAndroid* target = layerAndroid->findById(layer);
3724 RenderLayer* owner = target->owningLayer();
3728 if (owner->stackingContext())
3729 owner->scrollToOffset(rect.fLeft, rect.fTop, true, false);
3733 //----------------------------------------------------------------------
3734 // Native JNI methods
3735 //----------------------------------------------------------------------
3736 static void RevealSelection(JNIEnv *env, jobject obj)
3738 GET_NATIVE_VIEW(env, obj)->revealSelection();
3741 static jstring RequestLabel(JNIEnv *env, jobject obj, int framePointer,
3744 return wtfStringToJstring(env, GET_NATIVE_VIEW(env, obj)->requestLabel(
3745 (WebCore::Frame*) framePointer, (WebCore::Node*) nodePointer));
3748 static void ClearContent(JNIEnv *env, jobject obj)
3750 #ifdef ANDROID_INSTRUMENT
3751 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
3753 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
3754 viewImpl->clearContent();
3757 static void UpdateFrameCacheIfLoading(JNIEnv *env, jobject obj)
3759 GET_NATIVE_VIEW(env, obj)->updateFrameCacheIfLoading();
3762 static void SetSize(JNIEnv *env, jobject obj, jint width, jint height,
3763 jint textWrapWidth, jfloat scale, jint screenWidth, jint screenHeight,
3764 jint anchorX, jint anchorY, jboolean ignoreHeight)
3766 #ifdef ANDROID_INSTRUMENT
3767 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
3769 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
3770 LOGV("webviewcore::nativeSetSize(%u %u)\n viewImpl: %p", (unsigned)width, (unsigned)height, viewImpl);
3771 LOG_ASSERT(viewImpl, "viewImpl not set in nativeSetSize");
3772 viewImpl->setSizeScreenWidthAndScale(width, height, textWrapWidth, scale,
3773 screenWidth, screenHeight, anchorX, anchorY, ignoreHeight);
3776 static void SetScrollOffset(JNIEnv *env, jobject obj, jint gen, jboolean sendScrollEvent, jint x, jint y)
3778 #ifdef ANDROID_INSTRUMENT
3779 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
3781 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
3782 LOG_ASSERT(viewImpl, "need viewImpl");
3784 viewImpl->setScrollOffset(gen, sendScrollEvent, x, y);
3787 static void SetGlobalBounds(JNIEnv *env, jobject obj, jint x, jint y, jint h,
3790 #ifdef ANDROID_INSTRUMENT
3791 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
3793 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
3794 LOG_ASSERT(viewImpl, "need viewImpl");
3796 viewImpl->setGlobalBounds(x, y, h, v);
3799 static jboolean Key(JNIEnv *env, jobject obj, jint keyCode, jint unichar,
3800 jint repeatCount, jboolean isShift, jboolean isAlt, jboolean isSym,
3803 #ifdef ANDROID_INSTRUMENT
3804 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
3806 return GET_NATIVE_VIEW(env, obj)->key(PlatformKeyboardEvent(keyCode,
3807 unichar, repeatCount, isDown, isShift, isAlt, isSym));
3810 static void Click(JNIEnv *env, jobject obj, int framePtr, int nodePtr, jboolean fake)
3812 #ifdef ANDROID_INSTRUMENT
3813 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
3815 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
3816 LOG_ASSERT(viewImpl, "viewImpl not set in Click");
3818 viewImpl->click(reinterpret_cast<WebCore::Frame*>(framePtr),
3819 reinterpret_cast<WebCore::Node*>(nodePtr), fake);
3822 static void ContentInvalidateAll(JNIEnv *env, jobject obj)
3824 GET_NATIVE_VIEW(env, obj)->contentInvalidateAll();
3827 static void DeleteSelection(JNIEnv *env, jobject obj, jint start, jint end,
3828 jint textGeneration)
3830 #ifdef ANDROID_INSTRUMENT
3831 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
3833 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
3834 viewImpl->deleteSelection(start, end, textGeneration);
3837 static void SetSelection(JNIEnv *env, jobject obj, jint start, jint end)
3839 #ifdef ANDROID_INSTRUMENT
3840 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
3842 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
3843 viewImpl->setSelection(start, end);
3846 static jstring ModifySelection(JNIEnv *env, jobject obj, jint direction, jint granularity)
3848 #ifdef ANDROID_INSTRUMENT
3849 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
3851 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
3852 String selectionString = viewImpl->modifySelection(direction, granularity);
3853 return wtfStringToJstring(env, selectionString);
3856 static void ReplaceTextfieldText(JNIEnv *env, jobject obj,
3857 jint oldStart, jint oldEnd, jstring replace, jint start, jint end,
3858 jint textGeneration)
3860 #ifdef ANDROID_INSTRUMENT
3861 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
3863 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
3864 WTF::String webcoreString = jstringToWtfString(env, replace);
3865 viewImpl->replaceTextfieldText(oldStart,
3866 oldEnd, webcoreString, start, end, textGeneration);
3869 static void PassToJs(JNIEnv *env, jobject obj,
3870 jint generation, jstring currentText, jint keyCode,
3871 jint keyValue, jboolean down, jboolean cap, jboolean fn, jboolean sym)
3873 #ifdef ANDROID_INSTRUMENT
3874 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
3876 WTF::String current = jstringToWtfString(env, currentText);
3877 GET_NATIVE_VIEW(env, obj)->passToJs(generation, current,
3878 PlatformKeyboardEvent(keyCode, keyValue, 0, down, cap, fn, sym));
3881 static void ScrollFocusedTextInput(JNIEnv *env, jobject obj, jfloat xPercent,
3884 #ifdef ANDROID_INSTRUMENT
3885 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
3887 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
3888 viewImpl->scrollFocusedTextInput(xPercent, y);
3891 static void SetFocusControllerActive(JNIEnv *env, jobject obj, jboolean active)
3893 #ifdef ANDROID_INSTRUMENT
3894 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
3896 LOGV("webviewcore::nativeSetFocusControllerActive()\n");
3897 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
3898 LOG_ASSERT(viewImpl, "viewImpl not set in nativeSetFocusControllerActive");
3899 viewImpl->setFocusControllerActive(active);
3902 static void SaveDocumentState(JNIEnv *env, jobject obj, jint frame)
3904 #ifdef ANDROID_INSTRUMENT
3905 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
3907 LOGV("webviewcore::nativeSaveDocumentState()\n");
3908 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
3909 LOG_ASSERT(viewImpl, "viewImpl not set in nativeSaveDocumentState");
3910 viewImpl->saveDocumentState((WebCore::Frame*) frame);
3913 void WebViewCore::addVisitedLink(const UChar* string, int length)
3915 if (m_groupForVisitedLinks)
3916 m_groupForVisitedLinks->addVisitedLink(string, length);
3919 static jint UpdateLayers(JNIEnv *env, jobject obj, jobject region)
3921 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
3922 BaseLayerAndroid* result = viewImpl->createBaseLayer();
3923 SkRegion* nativeRegion = GraphicsJNI::getNativeRegion(env, region);
3926 LayerAndroid* root = static_cast<LayerAndroid*>(result->getChild(0));
3928 root->bounds().roundOut(&bounds);
3929 nativeRegion->setRect(bounds);
3932 return reinterpret_cast<jint>(result);
3935 static jint RecordContent(JNIEnv *env, jobject obj, jobject region, jobject pt)
3937 #ifdef ANDROID_INSTRUMENT
3938 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
3940 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
3941 SkRegion* nativeRegion = GraphicsJNI::getNativeRegion(env, region);
3943 BaseLayerAndroid* result = viewImpl->recordContent(nativeRegion, &nativePt);
3944 GraphicsJNI::ipoint_to_jpoint(nativePt, env, pt);
3945 return reinterpret_cast<jint>(result);
3948 static void SplitContent(JNIEnv *env, jobject obj, jint content)
3950 #ifdef ANDROID_INSTRUMENT
3951 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
3953 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
3954 viewImpl->splitContent(reinterpret_cast<PictureSet*>(content));
3957 static void SendListBoxChoice(JNIEnv* env, jobject obj, jint choice)
3959 #ifdef ANDROID_INSTRUMENT
3960 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
3962 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
3963 LOG_ASSERT(viewImpl, "viewImpl not set in nativeSendListBoxChoice");
3964 viewImpl->popupReply(choice);
3967 // Set aside a predetermined amount of space in which to place the listbox
3968 // choices, to avoid unnecessary allocations.
3969 // The size here is arbitrary. We want the size to be at least as great as the
3970 // number of items in the average multiple-select listbox.
3971 #define PREPARED_LISTBOX_STORAGE 10
3973 static void SendListBoxChoices(JNIEnv* env, jobject obj, jbooleanArray jArray,
3976 #ifdef ANDROID_INSTRUMENT
3977 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
3979 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
3980 LOG_ASSERT(viewImpl, "viewImpl not set in nativeSendListBoxChoices");
3981 jboolean* ptrArray = env->GetBooleanArrayElements(jArray, 0);
3982 SkAutoSTMalloc<PREPARED_LISTBOX_STORAGE, int> storage(size);
3983 int* array = storage.get();
3985 for (int i = 0; i < size; i++) {
3990 env->ReleaseBooleanArrayElements(jArray, ptrArray, JNI_ABORT);
3991 viewImpl->popupReply(array, count);
3994 static jstring FindAddress(JNIEnv *env, jobject obj, jstring addr,
3995 jboolean caseInsensitive)
3997 #ifdef ANDROID_INSTRUMENT
3998 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
4002 int length = env->GetStringLength(addr);
4005 const jchar* addrChars = env->GetStringChars(addr, 0);
4007 bool success = CacheBuilder::FindAddress(addrChars, length,
4008 &start, &end, caseInsensitive) == CacheBuilder::FOUND_COMPLETE;
4011 ret = env->NewString(addrChars + start, end - start);
4012 env->ReleaseStringChars(addr, addrChars);
4016 static jboolean HandleTouchEvent(JNIEnv *env, jobject obj, jint action, jintArray idArray,
4017 jintArray xArray, jintArray yArray,
4018 jint count, jint actionIndex, jint metaState)
4020 #ifdef ANDROID_INSTRUMENT
4021 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
4023 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
4024 LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
4025 jint* ptrIdArray = env->GetIntArrayElements(idArray, 0);
4026 jint* ptrXArray = env->GetIntArrayElements(xArray, 0);
4027 jint* ptrYArray = env->GetIntArrayElements(yArray, 0);
4028 Vector<int> ids(count);
4029 Vector<IntPoint> points(count);
4030 for (int c = 0; c < count; c++) {
4031 ids[c] = ptrIdArray[c];
4032 points[c].setX(ptrXArray[c]);
4033 points[c].setY(ptrYArray[c]);
4035 env->ReleaseIntArrayElements(idArray, ptrIdArray, JNI_ABORT);
4036 env->ReleaseIntArrayElements(xArray, ptrXArray, JNI_ABORT);
4037 env->ReleaseIntArrayElements(yArray, ptrYArray, JNI_ABORT);
4039 return viewImpl->handleTouchEvent(action, ids, points, actionIndex, metaState);
4042 static void TouchUp(JNIEnv *env, jobject obj, jint touchGeneration,
4043 jint frame, jint node, jint x, jint y)
4045 #ifdef ANDROID_INSTRUMENT
4046 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
4048 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
4049 LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
4050 viewImpl->touchUp(touchGeneration,
4051 (WebCore::Frame*) frame, (WebCore::Node*) node, x, y);
4054 static jstring RetrieveHref(JNIEnv *env, jobject obj, jint x, jint y)
4056 #ifdef ANDROID_INSTRUMENT
4057 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
4059 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
4060 LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
4061 WTF::String result = viewImpl->retrieveHref(x, y);
4062 if (!result.isEmpty())
4063 return wtfStringToJstring(env, result);
4067 static jstring RetrieveAnchorText(JNIEnv *env, jobject obj, jint x, jint y)
4069 #ifdef ANDROID_INSTRUMENT
4070 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
4072 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
4073 LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
4074 WTF::String result = viewImpl->retrieveAnchorText(x, y);
4075 if (!result.isEmpty())
4076 return wtfStringToJstring(env, result);
4080 static jstring RetrieveImageSource(JNIEnv *env, jobject obj, jint x, jint y)
4082 WTF::String result = GET_NATIVE_VIEW(env, obj)->retrieveImageSource(x, y);
4083 return !result.isEmpty() ? wtfStringToJstring(env, result) : 0;
4086 static void StopPaintingCaret(JNIEnv *env, jobject obj)
4088 GET_NATIVE_VIEW(env, obj)->setShouldPaintCaret(false);
4091 static void MoveFocus(JNIEnv *env, jobject obj, jint framePtr, jint nodePtr)
4093 #ifdef ANDROID_INSTRUMENT
4094 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
4096 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
4097 LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
4098 viewImpl->moveFocus((WebCore::Frame*) framePtr, (WebCore::Node*) nodePtr);
4101 static void MoveMouse(JNIEnv *env, jobject obj, jint frame,
4104 #ifdef ANDROID_INSTRUMENT
4105 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
4107 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
4108 LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
4109 viewImpl->moveMouse((WebCore::Frame*) frame, x, y);
4112 static void MoveMouseIfLatest(JNIEnv *env, jobject obj, jint moveGeneration,
4113 jint frame, jint x, jint y)
4115 #ifdef ANDROID_INSTRUMENT
4116 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
4118 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
4119 LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
4120 viewImpl->moveMouseIfLatest(moveGeneration,
4121 (WebCore::Frame*) frame, x, y);
4124 static void UpdateFrameCache(JNIEnv *env, jobject obj)
4126 #ifdef ANDROID_INSTRUMENT
4127 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
4129 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
4130 LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
4131 viewImpl->updateFrameCache();
4134 static jint GetContentMinPrefWidth(JNIEnv *env, jobject obj)
4136 #ifdef ANDROID_INSTRUMENT
4137 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
4139 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
4140 LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
4142 WebCore::Frame* frame = viewImpl->mainFrame();
4144 WebCore::Document* document = frame->document();
4146 WebCore::RenderObject* renderer = document->renderer();
4147 if (renderer && renderer->isRenderView()) {
4148 return renderer->minPreferredLogicalWidth();
4155 static void SetViewportSettingsFromNative(JNIEnv *env, jobject obj)
4157 #ifdef ANDROID_INSTRUMENT
4158 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
4160 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
4161 LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
4163 WebCore::Settings* s = viewImpl->mainFrame()->page()->settings();
4167 #ifdef ANDROID_META_SUPPORT
4168 env->SetIntField(obj, gWebViewCoreFields.m_viewportWidth, s->viewportWidth());
4169 env->SetIntField(obj, gWebViewCoreFields.m_viewportHeight, s->viewportHeight());
4170 env->SetIntField(obj, gWebViewCoreFields.m_viewportInitialScale, s->viewportInitialScale());
4171 env->SetIntField(obj, gWebViewCoreFields.m_viewportMinimumScale, s->viewportMinimumScale());
4172 env->SetIntField(obj, gWebViewCoreFields.m_viewportMaximumScale, s->viewportMaximumScale());
4173 env->SetBooleanField(obj, gWebViewCoreFields.m_viewportUserScalable, s->viewportUserScalable());
4174 env->SetIntField(obj, gWebViewCoreFields.m_viewportDensityDpi, s->viewportTargetDensityDpi());
4178 static void SetBackgroundColor(JNIEnv *env, jobject obj, jint color)
4180 #ifdef ANDROID_INSTRUMENT
4181 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
4183 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
4184 LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
4186 viewImpl->setBackgroundColor((SkColor) color);
4189 static void DumpDomTree(JNIEnv *env, jobject obj, jboolean useFile)
4191 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
4192 LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
4194 viewImpl->dumpDomTree(useFile);
4197 static void DumpRenderTree(JNIEnv *env, jobject obj, jboolean useFile)
4199 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
4200 LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
4202 viewImpl->dumpRenderTree(useFile);
4205 static void DumpNavTree(JNIEnv *env, jobject obj)
4207 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
4208 LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
4210 viewImpl->dumpNavTree();
4213 static void DumpV8Counters(JNIEnv*, jobject)
4216 #ifdef ANDROID_INSTRUMENT
4217 V8Counters::dumpCounters();
4222 static void SetJsFlags(JNIEnv *env, jobject obj, jstring flags)
4225 WTF::String flagsString = jstringToWtfString(env, flags);
4226 WTF::CString utf8String = flagsString.utf8();
4227 WebCore::ScriptController::setFlags(utf8String.data(), utf8String.length());
4232 // Called from the Java side to set a new quota for the origin or new appcache
4233 // max size in response to a notification that the original quota was exceeded or
4234 // that the appcache has reached its maximum size.
4235 static void SetNewStorageLimit(JNIEnv* env, jobject obj, jlong quota) {
4236 #if ENABLE(DATABASE) || ENABLE(OFFLINE_WEB_APPLICATIONS)
4237 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
4238 Frame* frame = viewImpl->mainFrame();
4240 // The main thread is blocked awaiting this response, so now we can wake it
4242 ChromeClientAndroid* chromeC = static_cast<ChromeClientAndroid*>(frame->page()->chrome()->client());
4243 chromeC->wakeUpMainThreadWithNewQuota(quota);
4247 // Called from Java to provide a Geolocation permission state for the specified origin.
4248 static void GeolocationPermissionsProvide(JNIEnv* env, jobject obj, jstring origin, jboolean allow, jboolean remember) {
4249 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
4250 Frame* frame = viewImpl->mainFrame();
4252 ChromeClientAndroid* chromeClient = static_cast<ChromeClientAndroid*>(frame->page()->chrome()->client());
4253 chromeClient->provideGeolocationPermissions(jstringToWtfString(env, origin), allow, remember);
4256 static void RegisterURLSchemeAsLocal(JNIEnv* env, jobject obj, jstring scheme) {
4257 #ifdef ANDROID_INSTRUMENT
4258 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
4260 WebCore::SchemeRegistry::registerURLSchemeAsLocal(jstringToWtfString(env, scheme));
4263 static bool FocusBoundsChanged(JNIEnv* env, jobject obj)
4265 return GET_NATIVE_VIEW(env, obj)->focusBoundsChanged();
4268 static void Pause(JNIEnv* env, jobject obj)
4270 // This is called for the foreground tab when the browser is put to the
4271 // background (and also for any tab when it is put to the background of the
4272 // browser). The browser can only be killed by the system when it is in the
4273 // background, so saving the Geolocation permission state now ensures that
4274 // is maintained when the browser is killed.
4275 ChromeClient* chromeClient = GET_NATIVE_VIEW(env, obj)->mainFrame()->page()->chrome()->client();
4276 ChromeClientAndroid* chromeClientAndroid = static_cast<ChromeClientAndroid*>(chromeClient);
4277 chromeClientAndroid->storeGeolocationPermissions();
4279 Frame* mainFrame = GET_NATIVE_VIEW(env, obj)->mainFrame();
4280 for (Frame* frame = mainFrame; frame; frame = frame->tree()->traverseNext()) {
4281 Geolocation* geolocation = frame->domWindow()->navigator()->optionalGeolocation();
4283 geolocation->suspend();
4286 GET_NATIVE_VIEW(env, obj)->deviceMotionAndOrientationManager()->maybeSuspendClients();
4289 SkANP::InitEvent(&event, kLifecycle_ANPEventType);
4290 event.data.lifecycle.action = kPause_ANPLifecycleAction;
4291 GET_NATIVE_VIEW(env, obj)->sendPluginEvent(event);
4293 GET_NATIVE_VIEW(env, obj)->setIsPaused(true);
4296 static void Resume(JNIEnv* env, jobject obj)
4298 Frame* mainFrame = GET_NATIVE_VIEW(env, obj)->mainFrame();
4299 for (Frame* frame = mainFrame; frame; frame = frame->tree()->traverseNext()) {
4300 Geolocation* geolocation = frame->domWindow()->navigator()->optionalGeolocation();
4302 geolocation->resume();
4305 GET_NATIVE_VIEW(env, obj)->deviceMotionAndOrientationManager()->maybeResumeClients();
4308 SkANP::InitEvent(&event, kLifecycle_ANPEventType);
4309 event.data.lifecycle.action = kResume_ANPLifecycleAction;
4310 GET_NATIVE_VIEW(env, obj)->sendPluginEvent(event);
4312 GET_NATIVE_VIEW(env, obj)->setIsPaused(false);
4315 static void FreeMemory(JNIEnv* env, jobject obj)
4318 SkANP::InitEvent(&event, kLifecycle_ANPEventType);
4319 event.data.lifecycle.action = kFreeMemory_ANPLifecycleAction;
4320 GET_NATIVE_VIEW(env, obj)->sendPluginEvent(event);
4323 static void ProvideVisitedHistory(JNIEnv *env, jobject obj, jobject hist)
4325 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
4326 LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
4328 jobjectArray array = static_cast<jobjectArray>(hist);
4330 jsize len = env->GetArrayLength(array);
4331 for (jsize i = 0; i < len; i++) {
4332 jstring item = static_cast<jstring>(env->GetObjectArrayElement(array, i));
4333 const UChar* str = static_cast<const UChar*>(env->GetStringChars(item, 0));
4334 jsize len = env->GetStringLength(item);
4335 viewImpl->addVisitedLink(str, len);
4336 env->ReleaseStringChars(item, str);
4337 env->DeleteLocalRef(item);
4341 // Notification from the UI thread that the plugin's full-screen surface has been discarded
4342 static void FullScreenPluginHidden(JNIEnv* env, jobject obj, jint npp)
4344 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
4345 PluginWidgetAndroid* plugin = viewImpl->getPluginWidget((NPP)npp);
4347 plugin->exitFullScreen(false);
4350 static WebCore::IntRect jrect_to_webrect(JNIEnv* env, jobject obj)
4353 GraphicsJNI::get_jrect(env, obj, &L, &T, &R, &B);
4354 return WebCore::IntRect(L, T, R - L, B - T);
4357 static bool ValidNodeAndBounds(JNIEnv *env, jobject obj, int frame, int node,
4360 IntRect nativeRect = jrect_to_webrect(env, rect);
4361 return GET_NATIVE_VIEW(env, obj)->validNodeAndBounds(
4362 reinterpret_cast<Frame*>(frame),
4363 reinterpret_cast<Node*>(node), nativeRect);
4366 static jobject GetTouchHighlightRects(JNIEnv* env, jobject obj, jint x, jint y, jint slop)
4368 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
4371 Vector<IntRect> rects = viewImpl->getTouchHighlightRects(x, y, slop);
4372 if (rects.isEmpty())
4375 jclass arrayClass = env->FindClass("java/util/ArrayList");
4376 LOG_ASSERT(arrayClass, "Could not find java/util/ArrayList");
4377 jmethodID init = env->GetMethodID(arrayClass, "<init>", "(I)V");
4378 LOG_ASSERT(init, "Could not find constructor for ArrayList");
4379 jobject array = env->NewObject(arrayClass, init, rects.size());
4380 LOG_ASSERT(array, "Could not create a new ArrayList");
4381 jmethodID add = env->GetMethodID(arrayClass, "add", "(Ljava/lang/Object;)Z");
4382 LOG_ASSERT(add, "Could not find add method on ArrayList");
4383 jclass rectClass = env->FindClass("android/graphics/Rect");
4384 LOG_ASSERT(rectClass, "Could not find android/graphics/Rect");
4385 jmethodID rectinit = env->GetMethodID(rectClass, "<init>", "(IIII)V");
4386 LOG_ASSERT(rectinit, "Could not find init method on Rect");
4388 for (size_t i = 0; i < rects.size(); i++) {
4389 jobject rect = env->NewObject(rectClass, rectinit, rects[i].x(),
4390 rects[i].y(), rects[i].right(), rects[i].bottom());
4392 env->CallBooleanMethod(array, add, rect);
4393 env->DeleteLocalRef(rect);
4397 env->DeleteLocalRef(rectClass);
4398 env->DeleteLocalRef(arrayClass);
4402 static void AutoFillForm(JNIEnv* env, jobject obj, jint queryId)
4404 #if ENABLE(WEB_AUTOFILL)
4405 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
4409 WebCore::Frame* frame = viewImpl->mainFrame();
4411 EditorClientAndroid* editorC = static_cast<EditorClientAndroid*>(frame->page()->editorClient());
4412 WebAutoFill* autoFill = editorC->getAutoFill();
4413 autoFill->fillFormFields(queryId);
4418 static void ScrollRenderLayer(JNIEnv* env, jobject obj, jint layer, jobject jRect)
4421 GraphicsJNI::jrect_to_rect(env, jRect, &rect);
4422 GET_NATIVE_VIEW(env, obj)->scrollRenderLayer(layer, rect);
4425 // ----------------------------------------------------------------------------
4430 static JNINativeMethod gJavaWebViewCoreMethods[] = {
4431 { "nativeClearContent", "()V",
4432 (void*) ClearContent },
4433 { "nativeFocusBoundsChanged", "()Z",
4434 (void*) FocusBoundsChanged } ,
4435 { "nativeKey", "(IIIZZZZ)Z",
4437 { "nativeClick", "(IIZ)V",
4439 { "nativeContentInvalidateAll", "()V",
4440 (void*) ContentInvalidateAll },
4441 { "nativeSendListBoxChoices", "([ZI)V",
4442 (void*) SendListBoxChoices },
4443 { "nativeSendListBoxChoice", "(I)V",
4444 (void*) SendListBoxChoice },
4445 { "nativeSetSize", "(IIIFIIIIZ)V",
4447 { "nativeSetScrollOffset", "(IZII)V",
4448 (void*) SetScrollOffset },
4449 { "nativeSetGlobalBounds", "(IIII)V",
4450 (void*) SetGlobalBounds },
4451 { "nativeSetSelection", "(II)V",
4452 (void*) SetSelection } ,
4453 { "nativeModifySelection", "(II)Ljava/lang/String;",
4454 (void*) ModifySelection },
4455 { "nativeDeleteSelection", "(III)V",
4456 (void*) DeleteSelection } ,
4457 { "nativeReplaceTextfieldText", "(IILjava/lang/String;III)V",
4458 (void*) ReplaceTextfieldText } ,
4459 { "nativeMoveFocus", "(II)V",
4460 (void*) MoveFocus },
4461 { "nativeMoveMouse", "(III)V",
4462 (void*) MoveMouse },
4463 { "nativeMoveMouseIfLatest", "(IIII)V",
4464 (void*) MoveMouseIfLatest },
4465 { "passToJs", "(ILjava/lang/String;IIZZZZ)V",
4467 { "nativeScrollFocusedTextInput", "(FI)V",
4468 (void*) ScrollFocusedTextInput },
4469 { "nativeSetFocusControllerActive", "(Z)V",
4470 (void*) SetFocusControllerActive },
4471 { "nativeSaveDocumentState", "(I)V",
4472 (void*) SaveDocumentState },
4473 { "nativeFindAddress", "(Ljava/lang/String;Z)Ljava/lang/String;",
4474 (void*) FindAddress },
4475 { "nativeHandleTouchEvent", "(I[I[I[IIII)Z",
4476 (void*) HandleTouchEvent },
4477 { "nativeTouchUp", "(IIIII)V",
4479 { "nativeRetrieveHref", "(II)Ljava/lang/String;",
4480 (void*) RetrieveHref },
4481 { "nativeRetrieveAnchorText", "(II)Ljava/lang/String;",
4482 (void*) RetrieveAnchorText },
4483 { "nativeRetrieveImageSource", "(II)Ljava/lang/String;",
4484 (void*) RetrieveImageSource },
4485 { "nativeStopPaintingCaret", "()V",
4486 (void*) StopPaintingCaret },
4487 { "nativeUpdateFrameCache", "()V",
4488 (void*) UpdateFrameCache },
4489 { "nativeGetContentMinPrefWidth", "()I",
4490 (void*) GetContentMinPrefWidth },
4491 { "nativeUpdateLayers", "(Landroid/graphics/Region;)I",
4492 (void*) UpdateLayers },
4493 { "nativeRecordContent", "(Landroid/graphics/Region;Landroid/graphics/Point;)I",
4494 (void*) RecordContent },
4495 { "setViewportSettingsFromNative", "()V",
4496 (void*) SetViewportSettingsFromNative },
4497 { "nativeSplitContent", "(I)V",
4498 (void*) SplitContent },
4499 { "nativeSetBackgroundColor", "(I)V",
4500 (void*) SetBackgroundColor },
4501 { "nativeRegisterURLSchemeAsLocal", "(Ljava/lang/String;)V",
4502 (void*) RegisterURLSchemeAsLocal },
4503 { "nativeDumpDomTree", "(Z)V",
4504 (void*) DumpDomTree },
4505 { "nativeDumpRenderTree", "(Z)V",
4506 (void*) DumpRenderTree },
4507 { "nativeDumpNavTree", "()V",
4508 (void*) DumpNavTree },
4509 { "nativeDumpV8Counters", "()V",
4510 (void*) DumpV8Counters },
4511 { "nativeSetNewStorageLimit", "(J)V",
4512 (void*) SetNewStorageLimit },
4513 { "nativeGeolocationPermissionsProvide", "(Ljava/lang/String;ZZ)V",
4514 (void*) GeolocationPermissionsProvide },
4515 { "nativePause", "()V", (void*) Pause },
4516 { "nativeResume", "()V", (void*) Resume },
4517 { "nativeFreeMemory", "()V", (void*) FreeMemory },
4518 { "nativeSetJsFlags", "(Ljava/lang/String;)V", (void*) SetJsFlags },
4519 { "nativeRequestLabel", "(II)Ljava/lang/String;",
4520 (void*) RequestLabel },
4521 { "nativeRevealSelection", "()V", (void*) RevealSelection },
4522 { "nativeUpdateFrameCacheIfLoading", "()V",
4523 (void*) UpdateFrameCacheIfLoading },
4524 { "nativeProvideVisitedHistory", "([Ljava/lang/String;)V",
4525 (void*) ProvideVisitedHistory },
4526 { "nativeFullScreenPluginHidden", "(I)V",
4527 (void*) FullScreenPluginHidden },
4528 { "nativeValidNodeAndBounds", "(IILandroid/graphics/Rect;)Z",
4529 (void*) ValidNodeAndBounds },
4530 { "nativeGetTouchHighlightRects", "(III)Ljava/util/ArrayList;",
4531 (void*) GetTouchHighlightRects },
4532 { "nativeAutoFillForm", "(I)V",
4533 (void*) AutoFillForm },
4534 { "nativeScrollLayer", "(ILandroid/graphics/Rect;)V",
4535 (void*) ScrollRenderLayer },
4538 int registerWebViewCore(JNIEnv* env)
4540 jclass widget = env->FindClass("android/webkit/WebViewCore");
4542 "Unable to find class android/webkit/WebViewCore");
4543 gWebViewCoreFields.m_nativeClass = env->GetFieldID(widget, "mNativeClass",
4545 LOG_ASSERT(gWebViewCoreFields.m_nativeClass,
4546 "Unable to find android/webkit/WebViewCore.mNativeClass");
4547 gWebViewCoreFields.m_viewportWidth = env->GetFieldID(widget,
4548 "mViewportWidth", "I");
4549 LOG_ASSERT(gWebViewCoreFields.m_viewportWidth,
4550 "Unable to find android/webkit/WebViewCore.mViewportWidth");
4551 gWebViewCoreFields.m_viewportHeight = env->GetFieldID(widget,
4552 "mViewportHeight", "I");
4553 LOG_ASSERT(gWebViewCoreFields.m_viewportHeight,
4554 "Unable to find android/webkit/WebViewCore.mViewportHeight");
4555 gWebViewCoreFields.m_viewportInitialScale = env->GetFieldID(widget,
4556 "mViewportInitialScale", "I");
4557 LOG_ASSERT(gWebViewCoreFields.m_viewportInitialScale,
4558 "Unable to find android/webkit/WebViewCore.mViewportInitialScale");
4559 gWebViewCoreFields.m_viewportMinimumScale = env->GetFieldID(widget,
4560 "mViewportMinimumScale", "I");
4561 LOG_ASSERT(gWebViewCoreFields.m_viewportMinimumScale,
4562 "Unable to find android/webkit/WebViewCore.mViewportMinimumScale");
4563 gWebViewCoreFields.m_viewportMaximumScale = env->GetFieldID(widget,
4564 "mViewportMaximumScale", "I");
4565 LOG_ASSERT(gWebViewCoreFields.m_viewportMaximumScale,
4566 "Unable to find android/webkit/WebViewCore.mViewportMaximumScale");
4567 gWebViewCoreFields.m_viewportUserScalable = env->GetFieldID(widget,
4568 "mViewportUserScalable", "Z");
4569 LOG_ASSERT(gWebViewCoreFields.m_viewportUserScalable,
4570 "Unable to find android/webkit/WebViewCore.mViewportUserScalable");
4571 gWebViewCoreFields.m_viewportDensityDpi = env->GetFieldID(widget,
4572 "mViewportDensityDpi", "I");
4573 LOG_ASSERT(gWebViewCoreFields.m_viewportDensityDpi,
4574 "Unable to find android/webkit/WebViewCore.mViewportDensityDpi");
4575 gWebViewCoreFields.m_webView = env->GetFieldID(widget,
4576 "mWebView", "Landroid/webkit/WebView;");
4577 LOG_ASSERT(gWebViewCoreFields.m_webView,
4578 "Unable to find android/webkit/WebViewCore.mWebView");
4579 gWebViewCoreFields.m_drawIsPaused = env->GetFieldID(widget,
4580 "mDrawIsPaused", "Z");
4581 LOG_ASSERT(gWebViewCoreFields.m_drawIsPaused,
4582 "Unable to find android/webkit/WebViewCore.mDrawIsPaused");
4583 gWebViewCoreFields.m_lowMemoryUsageMb = env->GetFieldID(widget, "mLowMemoryUsageThresholdMb", "I");
4584 gWebViewCoreFields.m_highMemoryUsageMb = env->GetFieldID(widget, "mHighMemoryUsageThresholdMb", "I");
4585 gWebViewCoreFields.m_highUsageDeltaMb = env->GetFieldID(widget, "mHighUsageDeltaMb", "I");
4587 gWebViewCoreStaticMethods.m_isSupportedMediaMimeType =
4588 env->GetStaticMethodID(widget, "isSupportedMediaMimeType", "(Ljava/lang/String;)Z");
4589 LOG_FATAL_IF(!gWebViewCoreStaticMethods.m_isSupportedMediaMimeType,
4590 "Could not find static method isSupportedMediaMimeType from WebViewCore");
4592 env->DeleteLocalRef(widget);
4594 return jniRegisterNativeMethods(env, "android/webkit/WebViewCore",
4595 gJavaWebViewCoreMethods, NELEM(gJavaWebViewCoreMethods));
4598 } /* namespace android */