WebViewCore.cpp revision 31afed8bf83b9f656fb76216c2f41e3971ae390d
1/* 2 * Copyright 2006, The Android Open Source Project 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * * Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * * Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY 14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26#define LOG_TAG "webcoreglue" 27 28#include "config.h" 29#include "WebViewCore.h" 30 31#include "AccessibilityObject.h" 32#include "Attribute.h" 33#include "BaseLayerAndroid.h" 34#include "CachedNode.h" 35#include "CachedRoot.h" 36#include "Chrome.h" 37#include "ChromeClientAndroid.h" 38#include "ChromiumIncludes.h" 39#include "ClientRect.h" 40#include "ClientRectList.h" 41#include "Color.h" 42#include "CSSPropertyNames.h" 43#include "CSSValueKeywords.h" 44#include "DatabaseTracker.h" 45#include "Document.h" 46#include "DOMWindow.h" 47#include "DOMSelection.h" 48#include "Element.h" 49#include "Editor.h" 50#include "EditorClientAndroid.h" 51#include "EventHandler.h" 52#include "EventNames.h" 53#include "ExceptionCode.h" 54#include "FocusController.h" 55#include "Font.h" 56#include "Frame.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" 84#include "Node.h" 85#include "NodeList.h" 86#include "Page.h" 87#include "PageGroup.h" 88#include "PlatformKeyboardEvent.h" 89#include "PlatformString.h" 90#include "PluginWidgetAndroid.h" 91#include "PluginView.h" 92#include "Position.h" 93#include "ProgressTracker.h" 94#include "Range.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" 107#include "SkANP.h" 108#include "SkTemplates.h" 109#include "SkTDArray.h" 110#include "SkTypes.h" 111#include "SkCanvas.h" 112#include "SkPicture.h" 113#include "SkUtils.h" 114#include "Text.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" 122#include "markup.h" 123 124#include <JNIHelp.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> 130 131#if USE(V8) 132#include "ScriptController.h" 133#include "V8Counters.h" 134#include <wtf/text/CString.h> 135#endif 136 137#if DEBUG_NAV_UI 138#include "SkTime.h" 139#endif 140 141#if ENABLE(TOUCH_EVENTS) // Android 142#include "PlatformTouchEvent.h" 143#endif 144 145#ifdef ANDROID_DOM_LOGGING 146#include "AndroidLog.h" 147#include "RenderTreeAsText.h" 148#include <wtf/text/CString.h> 149 150FILE* gDomTreeFile = 0; 151FILE* gRenderTreeFile = 0; 152#endif 153 154#ifdef ANDROID_INSTRUMENT 155#include "TimeCounter.h" 156#endif 157 158#if USE(ACCELERATED_COMPOSITING) 159#include "GraphicsLayerAndroid.h" 160#include "RenderLayerCompositor.h" 161#endif 162 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 165 is record them. 166 */ 167#define PICT_RECORD_FLAGS SkPicture::kUsePathBoundsForClip_RecordingFlag 168 169//////////////////////////////////////////////////////////////////////////////////////////////// 170 171namespace android { 172 173static SkTDArray<WebViewCore*> gInstanceList; 174 175void WebViewCore::addInstance(WebViewCore* inst) { 176 *gInstanceList.append() = inst; 177} 178 179void WebViewCore::removeInstance(WebViewCore* inst) { 180 int index = gInstanceList.find(inst); 181 LOG_ASSERT(index >= 0, "RemoveInstance inst not found"); 182 if (index >= 0) { 183 gInstanceList.removeShuffle(index); 184 } 185} 186 187bool WebViewCore::isInstance(WebViewCore* inst) { 188 return gInstanceList.find(inst) >= 0; 189} 190 191jobject WebViewCore::getApplicationContext() { 192 193 // check to see if there is a valid webviewcore object 194 if (gInstanceList.isEmpty()) 195 return 0; 196 197 // get the context from the webview 198 jobject context = gInstanceList[0]->getContext(); 199 200 if (!context) 201 return 0; 202 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); 209 checkException(env); 210 return result; 211} 212 213 214struct WebViewCoreStaticMethods { 215 jmethodID m_isSupportedMediaMimeType; 216} gWebViewCoreStaticMethods; 217 218// Check whether a media mimeType is supported in Android media framework. 219bool 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); 225 checkException(env); 226 env->DeleteLocalRef(webViewCore); 227 env->DeleteLocalRef(jMimeType); 228 229 return val; 230} 231 232// ---------------------------------------------------------------------------- 233 234#define GET_NATIVE_VIEW(env, obj) ((WebViewCore*)env->GetIntField(obj, gWebViewCoreFields.m_nativeClass)) 235 236// Field ids for WebViewCore 237struct 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; 246 jfieldID m_webView; 247 jfieldID m_drawIsPaused; 248 jfieldID m_lowMemoryUsageMb; 249 jfieldID m_highMemoryUsageMb; 250 jfieldID m_highUsageDeltaMb; 251} gWebViewCoreFields; 252 253// ---------------------------------------------------------------------------- 254 255struct WebViewCore::JavaGlue { 256 jweak m_obj; 257 jmethodID m_scrollTo; 258 jmethodID m_contentDraw; 259 jmethodID m_layersDraw; 260 jmethodID m_requestListBox; 261 jmethodID m_openFileChooser; 262 jmethodID m_requestSingleListBox; 263 jmethodID m_jsAlert; 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); 307 } 308}; 309 310/* 311 * WebViewCore Implementation 312 */ 313 314static jmethodID GetJMethod(JNIEnv* env, jclass clazz, const char name[], const char signature[]) 315{ 316 jmethodID m = env->GetMethodID(clazz, name, signature); 317 LOG_ASSERT(m, "Could not find method %s", name); 318 return m; 319} 320 321Mutex WebViewCore::gFrameCacheMutex; 322Mutex WebViewCore::gButtonMutex; 323Mutex WebViewCore::gCursorBoundsMutex; 324 325WebViewCore::WebViewCore(JNIEnv* env, jobject javaWebViewCore, WebCore::Frame* mainframe) 326 : m_pluginInvalTimer(this, &WebViewCore::pluginInvalTimerFired) 327 , m_deviceMotionAndOrientationManager(this) 328{ 329 m_mainFrame = mainframe; 330 331 m_popupReply = 0; 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; 340 m_screenWidth = 320; 341 m_textWrapWidth = 320; 342 m_scale = 1; 343#if ENABLE(TOUCH_EVENTS) 344 m_forwardingTouchEvents = false; 345#endif 346 m_isPaused = false; 347 m_screenOnCounter = 0; 348 m_shouldPaintCaret = true; 349 350 LOG_ASSERT(m_mainFrame, "Uh oh, somehow a frameview was made without an initial frame!"); 351 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"); 400#if ENABLE(VIDEO) 401 m_javaGlue->m_enterFullscreenForVideoLayer = GetJMethod(env, clazz, "enterFullscreenForVideoLayer", "(ILjava/lang/String;)V"); 402#endif 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); 406 407 env->SetIntField(javaWebViewCore, gWebViewCoreFields.m_nativeClass, (jint)this); 408 409 m_scrollOffsetX = m_scrollOffsetY = 0; 410 411 PageGroup::setShouldTrackVisitedLinks(true); 412 413 reset(true); 414 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)); 418 419 WebViewCore::addInstance(this); 420 421#if USE(CHROME_NETWORK_STACK) 422 AndroidNetworkLibraryImpl::InitWithApplicationContext(env, 0); 423#endif 424} 425 426WebViewCore::~WebViewCore() 427{ 428 WebViewCore::removeInstance(this); 429 430 // Release the focused view 431 Release(m_popupReply); 432 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; 437 } 438 delete m_javaGlue; 439 delete m_frameCacheKit; 440 delete m_navPictureKit; 441} 442 443WebViewCore* WebViewCore::getWebViewCore(const WebCore::FrameView* view) 444{ 445 return getWebViewCore(static_cast<const WebCore::ScrollView*>(view)); 446} 447 448WebViewCore* WebViewCore::getWebViewCore(const WebCore::ScrollView* view) 449{ 450 if (!view) 451 return 0; 452 453 WebFrameView* webFrameView = static_cast<WebFrameView*>(view->platformWidget()); 454 if (!webFrameView) 455 return 0; 456 return webFrameView->webViewCore(); 457} 458 459void WebViewCore::reset(bool fromConstructor) 460{ 461 DBG_SET_LOG(""); 462 if (fromConstructor) { 463 m_frameCacheKit = 0; 464 m_navPictureKit = 0; 465 } else { 466 gFrameCacheMutex.lock(); 467 delete m_frameCacheKit; 468 delete m_navPictureKit; 469 m_frameCacheKit = 0; 470 m_navPictureKit = 0; 471 gFrameCacheMutex.unlock(); 472 } 473 474 m_lastFocused = 0; 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; 480 clearContent(); 481 m_updatedFrameCache = true; 482 m_frameCacheOutOfDate = true; 483 m_skipContentDraw = false; 484 m_findIsUp = false; 485 m_domtree_version = 0; 486 m_check_domtree_version = true; 487 m_progressDone = false; 488 m_hasCursorBounds = false; 489 490 m_scrollOffsetX = 0; 491 m_scrollOffsetY = 0; 492 m_screenWidth = 0; 493 m_screenHeight = 0; 494 m_groupForVisitedLinks = 0; 495 m_currentNodeDomNavigationAxis = 0; 496} 497 498static bool layoutIfNeededRecursive(WebCore::Frame* f) 499{ 500 if (!f) 501 return true; 502 503 WebCore::FrameView* v = f->view(); 504 if (!v) 505 return true; 506 507 if (v->needsLayout()) 508 v->layout(f->tree()->parent()); 509 510 WebCore::Frame* child = f->tree()->firstChild(); 511 bool success = true; 512 while (child) { 513 success &= layoutIfNeededRecursive(child); 514 child = child->tree()->nextSibling(); 515 } 516 517 return success && !v->needsLayout(); 518} 519 520CacheBuilder& WebViewCore::cacheBuilder() 521{ 522 return FrameLoaderClientAndroid::get(m_mainFrame)->getCacheBuilder(); 523} 524 525WebCore::Node* WebViewCore::currentFocus() 526{ 527 return cacheBuilder().currentFocus(); 528} 529 530void WebViewCore::recordPicture(SkPicture* picture) 531{ 532 // if there is no document yet, just return 533 if (!m_mainFrame->document()) { 534 DBG_NAV_LOG("no document"); 535 return; 536 } 537 // Call layout to ensure that the contentWidth and contentHeight are correct 538 if (!layoutIfNeededRecursive(m_mainFrame)) { 539 DBG_NAV_LOG("layout failed"); 540 return; 541 } 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__); 549 550 // Copy m_buttons so we can pass it to our graphics context. 551 gButtonMutex.lock(); 552 WTF::Vector<Container> buttons(m_buttons); 553 gButtonMutex.unlock(); 554 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())); 559 560 gButtonMutex.lock(); 561 updateButtonList(&buttons); 562 gButtonMutex.unlock(); 563} 564 565void WebViewCore::recordPictureSet(PictureSet* content) 566{ 567 // if there is no document yet, just return 568 if (!m_mainFrame->document()) { 569 DBG_SET_LOG("!m_mainFrame->document()"); 570 return; 571 } 572 if (m_addInval.isEmpty()) { 573 DBG_SET_LOG("m_addInval.isEmpty()"); 574 return; 575 } 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 579 // doing that 580 m_skipContentDraw = true; 581 bool success = layoutIfNeededRecursive(m_mainFrame); 582 m_skipContentDraw = false; 583 584 // We may be mid-layout and thus cannot draw. 585 if (!success) 586 return; 587 588 { // collect WebViewCoreRecordTimeCounter after layoutIfNeededRecursive 589#ifdef ANDROID_INSTRUMENT 590 TimeCounterAuto counter(TimeCounter::WebViewCoreRecordTimeCounter); 591#endif 592 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(); 597 598 // Use the contents width and height as a starting point. 599 SkIRect contentRect; 600 contentRect.set(0, 0, width, height); 601 SkIRect total(contentRect); 602 603 // Traverse all the frames and add their sizes if they are in the visible 604 // rectangle. 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) { 611 int x = owner->x(); 612 int y = owner->y(); 613 614 // Traverse the tree up to the parent to find the absolute position 615 // of this frame. 616 WebCore::Frame* parent = frame->tree()->parent(); 617 while (parent) { 618 WebCore::RenderPart* parentOwner = parent->ownerRenderer(); 619 if (parentOwner) { 620 x += parentOwner->x(); 621 y += parentOwner->y(); 622 } 623 parent = parent->tree()->parent(); 624 } 625 // Use the owner dimensions so that padding and border are 626 // included. 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 633 // them here. 634 if (frameRect.width() > 1 && frameRect.height() > 1 635 && SkIRect::Intersects(total, frameRect)) 636 total.join(x, y, right, bottom); 637 } 638 } 639 640 // If the new total is larger than the content, resize the view to include 641 // all the content. 642 if (!contentRect.contains(total)) { 643 // Resize the view to change the overflow clip. 644 view->resize(total.fRight, total.fBottom); 645 646 // We have to force a layout in order for the clip to change. 647 m_mainFrame->contentRenderer()->setNeedsLayoutAndPrefWidthsRecalc(); 648 view->forceLayout(); 649 650 // Relayout similar to above 651 m_skipContentDraw = true; 652 bool success = layoutIfNeededRecursive(m_mainFrame); 653 m_skipContentDraw = false; 654 if (!success) 655 return; 656 657 // Set the computed content width 658 width = view->contentsWidth(); 659 height = view->contentsHeight(); 660 } 661 662 if (cacheBuilder().pictureSetDisabled()) 663 content->clear(); 664 665 content->checkDimensions(width, height, &m_addInval); 666 667 // Add the current inval rects to the PictureSet, and rebuild it. 668 content->add(m_addInval, 0, 0, false); 669 rebuildPictureSet(content); 670 671 } // WebViewCoreRecordTimeCounter 672 673 WebCore::Node* oldFocusNode = currentFocus(); 674 m_frameCacheOutOfDate = true; 675 WebCore::IntRect oldBounds; 676 int oldSelStart = 0; 677 int oldSelEnd = 0; 678 if (oldFocusNode) { 679 oldBounds = oldFocusNode->getRect(); 680 RenderObject* renderer = oldFocusNode->renderer(); 681 if (renderer && (renderer->isTextArea() || renderer->isTextField())) { 682 WebCore::RenderTextControl* rtc = 683 static_cast<WebCore::RenderTextControl*>(renderer); 684 oldSelStart = rtc->selectionStart(); 685 oldSelEnd = rtc->selectionEnd(); 686 } 687 } else 688 oldBounds = WebCore::IntRect(0,0,0,0); 689 unsigned latestVersion = 0; 690 if (m_check_domtree_version) { 691 // as domTreeVersion only increment, we can just check the sum to see 692 // whether we need to update the frame cache 693 for (Frame* frame = m_mainFrame; frame; frame = frame->tree()->traverseNext()) { 694 const Document* doc = frame->document(); 695 latestVersion += doc->domTreeVersion() + doc->styleVersion(); 696 } 697 } 698 DBG_NAV_LOGD("m_lastFocused=%p oldFocusNode=%p" 699 " m_lastFocusedBounds={%d,%d,%d,%d} oldBounds={%d,%d,%d,%d}" 700 " m_lastFocusedSelection={%d,%d} oldSelection={%d,%d}" 701 " m_check_domtree_version=%s latestVersion=%d m_domtree_version=%d", 702 m_lastFocused, oldFocusNode, 703 m_lastFocusedBounds.x(), m_lastFocusedBounds.y(), 704 m_lastFocusedBounds.width(), m_lastFocusedBounds.height(), 705 oldBounds.x(), oldBounds.y(), oldBounds.width(), oldBounds.height(), 706 m_lastFocusedSelStart, m_lastFocusedSelEnd, oldSelStart, oldSelEnd, 707 m_check_domtree_version ? "true" : "false", 708 latestVersion, m_domtree_version); 709 if (m_lastFocused == oldFocusNode && m_lastFocusedBounds == oldBounds 710 && m_lastFocusedSelStart == oldSelStart 711 && m_lastFocusedSelEnd == oldSelEnd 712 && !m_findIsUp 713 && (!m_check_domtree_version || latestVersion == m_domtree_version)) 714 { 715 return; 716 } 717 m_focusBoundsChanged |= m_lastFocused == oldFocusNode 718 && m_lastFocusedBounds != oldBounds; 719 m_lastFocused = oldFocusNode; 720 m_lastFocusedBounds = oldBounds; 721 m_lastFocusedSelStart = oldSelStart; 722 m_lastFocusedSelEnd = oldSelEnd; 723 m_domtree_version = latestVersion; 724 DBG_NAV_LOG("call updateFrameCache"); 725 updateFrameCache(); 726 if (m_findIsUp) { 727 LOG_ASSERT(m_javaGlue->m_obj, 728 "A Java widget was not associated with this view bridge!"); 729 JNIEnv* env = JSC::Bindings::getJNIEnv(); 730 env->CallVoidMethod(m_javaGlue->object(env).get(), 731 m_javaGlue->m_sendFindAgain); 732 checkException(env); 733 } 734} 735 736void WebViewCore::updateButtonList(WTF::Vector<Container>* buttons) 737{ 738 // All the entries in buttons are either updates of previous entries in 739 // m_buttons or they need to be added to it. 740 Container* end = buttons->end(); 741 for (Container* updatedContainer = buttons->begin(); 742 updatedContainer != end; updatedContainer++) { 743 bool updated = false; 744 // Search for a previous entry that references the same node as our new 745 // data 746 Container* lastPossibleMatch = m_buttons.end(); 747 for (Container* possibleMatch = m_buttons.begin(); 748 possibleMatch != lastPossibleMatch; possibleMatch++) { 749 if (updatedContainer->matches(possibleMatch->node())) { 750 // Update our record, and skip to the next one. 751 possibleMatch->setRect(updatedContainer->rect()); 752 updated = true; 753 break; 754 } 755 } 756 if (!updated) { 757 // This is a brand new button, so append it to m_buttons 758 m_buttons.append(*updatedContainer); 759 } 760 } 761 size_t i = 0; 762 // count will decrease each time one is removed, so check count each time. 763 while (i < m_buttons.size()) { 764 if (m_buttons[i].canBeRemoved()) { 765 m_buttons[i] = m_buttons.last(); 766 m_buttons.removeLast(); 767 } else { 768 i++; 769 } 770 } 771} 772 773// note: updateCursorBounds is called directly by the WebView thread 774// This needs to be called each time we call CachedRoot::setCursor() with 775// non-null CachedNode/CachedFrame, since otherwise the WebViewCore's data 776// about the cursor is incorrect. When we call setCursor(0,0), we need 777// to set hasCursorBounds to false. 778void WebViewCore::updateCursorBounds(const CachedRoot* root, 779 const CachedFrame* cachedFrame, const CachedNode* cachedNode) 780{ 781 LOG_ASSERT(root, "updateCursorBounds: root cannot be null"); 782 LOG_ASSERT(cachedNode, "updateCursorBounds: cachedNode cannot be null"); 783 LOG_ASSERT(cachedFrame, "updateCursorBounds: cachedFrame cannot be null"); 784 gCursorBoundsMutex.lock(); 785 m_hasCursorBounds = !cachedNode->isHidden(); 786 // If m_hasCursorBounds is false, we never look at the other 787 // values, so do not bother setting them. 788 if (m_hasCursorBounds) { 789 WebCore::IntRect bounds = cachedNode->bounds(cachedFrame); 790 if (m_cursorBounds != bounds) 791 DBG_NAV_LOGD("new cursor bounds=(%d,%d,w=%d,h=%d)", 792 bounds.x(), bounds.y(), bounds.width(), bounds.height()); 793 m_cursorBounds = bounds; 794 m_cursorHitBounds = cachedNode->hitBounds(cachedFrame); 795 m_cursorFrame = cachedFrame->framePointer(); 796 root->getSimulatedMousePosition(&m_cursorLocation); 797 m_cursorNode = cachedNode->nodePointer(); 798 } 799 gCursorBoundsMutex.unlock(); 800} 801 802void WebViewCore::clearContent() 803{ 804 DBG_SET_LOG(""); 805 m_content.clear(); 806 m_addInval.setEmpty(); 807 m_rebuildInval.setEmpty(); 808} 809 810bool WebViewCore::focusBoundsChanged() 811{ 812 bool result = m_focusBoundsChanged; 813 m_focusBoundsChanged = false; 814 return result; 815} 816 817SkPicture* WebViewCore::rebuildPicture(const SkIRect& inval) 818{ 819 WebCore::FrameView* view = m_mainFrame->view(); 820 int width = view->contentsWidth(); 821 int height = view->contentsHeight(); 822 SkPicture* picture = new SkPicture(); 823 SkAutoPictureRecord arp(picture, width, height, PICT_RECORD_FLAGS); 824 SkAutoMemoryUsageProbe mup(__FUNCTION__); 825 SkCanvas* recordingCanvas = arp.getRecordingCanvas(); 826 827 gButtonMutex.lock(); 828 WTF::Vector<Container> buttons(m_buttons); 829 gButtonMutex.unlock(); 830 831 WebCore::PlatformGraphicsContext pgc(recordingCanvas, &buttons); 832 WebCore::GraphicsContext gc(&pgc); 833 recordingCanvas->translate(-inval.fLeft, -inval.fTop); 834 recordingCanvas->save(); 835 view->platformWidget()->draw(&gc, WebCore::IntRect(inval.fLeft, 836 inval.fTop, inval.width(), inval.height())); 837 m_rebuildInval.op(inval, SkRegion::kUnion_Op); 838 DBG_SET_LOGD("m_rebuildInval={%d,%d,r=%d,b=%d}", 839 m_rebuildInval.getBounds().fLeft, m_rebuildInval.getBounds().fTop, 840 m_rebuildInval.getBounds().fRight, m_rebuildInval.getBounds().fBottom); 841 842 gButtonMutex.lock(); 843 updateButtonList(&buttons); 844 gButtonMutex.unlock(); 845 846 return picture; 847} 848 849void WebViewCore::rebuildPictureSet(PictureSet* pictureSet) 850{ 851 WebCore::FrameView* view = m_mainFrame->view(); 852 size_t size = pictureSet->size(); 853 for (size_t index = 0; index < size; index++) { 854 if (pictureSet->upToDate(index)) 855 continue; 856 const SkIRect& inval = pictureSet->bounds(index); 857 DBG_SET_LOGD("pictSet=%p [%d] {%d,%d,w=%d,h=%d}", pictureSet, index, 858 inval.fLeft, inval.fTop, inval.width(), inval.height()); 859 pictureSet->setPicture(index, rebuildPicture(inval)); 860 } 861 pictureSet->validate(__FUNCTION__); 862} 863 864BaseLayerAndroid* WebViewCore::createBaseLayer() 865{ 866 BaseLayerAndroid* base = new BaseLayerAndroid(); 867 base->setContent(m_content); 868 869 m_skipContentDraw = true; 870 bool layoutSucceeded = layoutIfNeededRecursive(m_mainFrame); 871 m_skipContentDraw = false; 872 // Layout only fails if called during a layout. 873 LOG_ASSERT(layoutSucceeded, "Can never be called recursively"); 874 875#if USE(ACCELERATED_COMPOSITING) 876 // We set the background color 877 if (m_mainFrame && m_mainFrame->document() 878 && m_mainFrame->document()->body()) { 879 Document* document = m_mainFrame->document(); 880 RefPtr<RenderStyle> style = document->styleForElementIgnoringPendingStylesheets(document->body()); 881 if (style->hasBackground()) { 882 Color color = style->visitedDependentColor(CSSPropertyBackgroundColor); 883 if (color.isValid() && color.alpha() > 0) 884 base->setBackgroundColor(color); 885 } 886 } 887 888 // We update the layers 889 ChromeClientAndroid* chromeC = static_cast<ChromeClientAndroid*>(m_mainFrame->page()->chrome()->client()); 890 GraphicsLayerAndroid* root = static_cast<GraphicsLayerAndroid*>(chromeC->layersSync()); 891 if (root) { 892 root->notifyClientAnimationStarted(); 893 LayerAndroid* copyLayer = new LayerAndroid(*root->contentLayer()); 894 base->addChild(copyLayer); 895 copyLayer->unref(); 896 } 897#endif 898 899 return base; 900} 901 902BaseLayerAndroid* WebViewCore::recordContent(SkRegion* region, SkIPoint* point) 903{ 904 DBG_SET_LOG("start"); 905 // If there is a pending style recalculation, just return. 906 if (m_mainFrame->document()->isPendingStyleRecalc()) { 907 DBG_SET_LOGD("recordContent: pending style recalc, ignoring."); 908 return 0; 909 } 910 float progress = (float) m_mainFrame->page()->progress()->estimatedProgress(); 911 m_progressDone = progress <= 0.0f || progress >= 1.0f; 912 recordPictureSet(&m_content); 913 if (!m_progressDone && m_content.isEmpty()) { 914 DBG_SET_LOGD("empty (progress=%g)", progress); 915 return 0; 916 } 917 region->set(m_addInval); 918 m_addInval.setEmpty(); 919#if USE(ACCELERATED_COMPOSITING) 920#else 921 region->op(m_rebuildInval, SkRegion::kUnion_Op); 922#endif 923 m_rebuildInval.setEmpty(); 924 point->fX = m_content.width(); 925 point->fY = m_content.height(); 926 DBG_SET_LOGD("region={%d,%d,r=%d,b=%d}", region->getBounds().fLeft, 927 region->getBounds().fTop, region->getBounds().fRight, 928 region->getBounds().fBottom); 929 DBG_SET_LOG("end"); 930 931 return createBaseLayer(); 932} 933 934void WebViewCore::splitContent(PictureSet* content) 935{ 936 bool layoutSucceeded = layoutIfNeededRecursive(m_mainFrame); 937 LOG_ASSERT(layoutSucceeded, "Can never be called recursively"); 938 content->split(&m_content); 939 rebuildPictureSet(&m_content); 940 content->set(m_content); 941} 942 943void WebViewCore::scrollTo(int x, int y, bool animate) 944{ 945 LOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!"); 946 947// LOGD("WebViewCore::scrollTo(%d %d)\n", x, y); 948 949 JNIEnv* env = JSC::Bindings::getJNIEnv(); 950 env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_scrollTo, 951 x, y, animate, false); 952 checkException(env); 953} 954 955void WebViewCore::sendNotifyProgressFinished() 956{ 957 LOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!"); 958 JNIEnv* env = JSC::Bindings::getJNIEnv(); 959 env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_sendNotifyProgressFinished); 960 checkException(env); 961} 962 963void WebViewCore::viewInvalidate(const WebCore::IntRect& rect) 964{ 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(), 968 m_javaGlue->m_sendViewInvalidate, 969 rect.x(), rect.y(), rect.maxX(), rect.maxY()); 970 checkException(env); 971} 972 973void WebViewCore::contentDraw() 974{ 975 JNIEnv* env = JSC::Bindings::getJNIEnv(); 976 env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_contentDraw); 977 checkException(env); 978} 979 980void WebViewCore::layersDraw() 981{ 982 JNIEnv* env = JSC::Bindings::getJNIEnv(); 983 env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_layersDraw); 984 checkException(env); 985} 986 987void WebViewCore::contentInvalidate(const WebCore::IntRect &r) 988{ 989 DBG_SET_LOGD("rect={%d,%d,w=%d,h=%d}", r.x(), r.y(), r.width(), r.height()); 990 SkIRect rect(r); 991 if (!rect.intersect(0, 0, INT_MAX, INT_MAX)) 992 return; 993 m_addInval.op(rect, SkRegion::kUnion_Op); 994 DBG_SET_LOGD("m_addInval={%d,%d,r=%d,b=%d}", 995 m_addInval.getBounds().fLeft, m_addInval.getBounds().fTop, 996 m_addInval.getBounds().fRight, m_addInval.getBounds().fBottom); 997 if (!m_skipContentDraw) 998 contentDraw(); 999} 1000 1001void WebViewCore::contentInvalidateAll() 1002{ 1003 WebCore::FrameView* view = m_mainFrame->view(); 1004 contentInvalidate(WebCore::IntRect(0, 0, 1005 view->contentsWidth(), view->contentsHeight())); 1006} 1007 1008void WebViewCore::offInvalidate(const WebCore::IntRect &r) 1009{ 1010 // FIXME: these invalidates are offscreen, and can be throttled or 1011 // deferred until the area is visible. For now, treat them as 1012 // regular invals so that drawing happens (inefficiently) for now. 1013 contentInvalidate(r); 1014} 1015 1016static int pin_pos(int x, int width, int targetWidth) 1017{ 1018 if (x + width > targetWidth) 1019 x = targetWidth - width; 1020 if (x < 0) 1021 x = 0; 1022 return x; 1023} 1024 1025void WebViewCore::didFirstLayout() 1026{ 1027 DEBUG_NAV_UI_LOGD("%s", __FUNCTION__); 1028 LOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!"); 1029 1030 const WebCore::KURL& url = m_mainFrame->document()->url(); 1031 if (url.isEmpty()) 1032 return; 1033 LOGV("::WebCore:: didFirstLayout %s", url.string().ascii().data()); 1034 1035 WebCore::FrameLoadType loadType = m_mainFrame->loader()->loadType(); 1036 1037 JNIEnv* env = JSC::Bindings::getJNIEnv(); 1038 env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_didFirstLayout, 1039 loadType == WebCore::FrameLoadTypeStandard 1040 // When redirect with locked history, we would like to reset the 1041 // scale factor. This is important for www.yahoo.com as it is 1042 // redirected to www.yahoo.com/?rs=1 on load. 1043 || loadType == WebCore::FrameLoadTypeRedirectWithLockedBackForwardList); 1044 checkException(env); 1045 1046 DBG_NAV_LOG("call updateFrameCache"); 1047 m_check_domtree_version = false; 1048 updateFrameCache(); 1049 m_history.setDidFirstLayout(true); 1050} 1051 1052void WebViewCore::updateViewport() 1053{ 1054 DEBUG_NAV_UI_LOGD("%s", __FUNCTION__); 1055 LOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!"); 1056 1057 JNIEnv* env = JSC::Bindings::getJNIEnv(); 1058 env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_updateViewport); 1059 checkException(env); 1060} 1061 1062void WebViewCore::restoreScale(float scale, float textWrapScale) 1063{ 1064 DEBUG_NAV_UI_LOGD("%s", __FUNCTION__); 1065 LOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!"); 1066 1067 JNIEnv* env = JSC::Bindings::getJNIEnv(); 1068 env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_restoreScale, scale, textWrapScale); 1069 checkException(env); 1070} 1071 1072void WebViewCore::needTouchEvents(bool need) 1073{ 1074 DEBUG_NAV_UI_LOGD("%s", __FUNCTION__); 1075 LOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!"); 1076 1077#if ENABLE(TOUCH_EVENTS) 1078 if (m_forwardingTouchEvents == need) 1079 return; 1080 1081 JNIEnv* env = JSC::Bindings::getJNIEnv(); 1082 env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_needTouchEvents, need); 1083 checkException(env); 1084 1085 m_forwardingTouchEvents = need; 1086#endif 1087} 1088 1089void WebViewCore::requestKeyboardWithSelection(const WebCore::Node* node, 1090 int selStart, int selEnd) 1091{ 1092 DEBUG_NAV_UI_LOGD("%s", __FUNCTION__); 1093 LOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!"); 1094 1095 JNIEnv* env = JSC::Bindings::getJNIEnv(); 1096 env->CallVoidMethod(m_javaGlue->object(env).get(), 1097 m_javaGlue->m_requestKeyboardWithSelection, 1098 reinterpret_cast<int>(node), selStart, selEnd, m_textGeneration); 1099 checkException(env); 1100} 1101 1102void WebViewCore::requestKeyboard(bool showKeyboard) 1103{ 1104 DEBUG_NAV_UI_LOGD("%s", __FUNCTION__); 1105 LOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!"); 1106 1107 JNIEnv* env = JSC::Bindings::getJNIEnv(); 1108 env->CallVoidMethod(m_javaGlue->object(env).get(), 1109 m_javaGlue->m_requestKeyboard, showKeyboard); 1110 checkException(env); 1111} 1112 1113void WebViewCore::notifyProgressFinished() 1114{ 1115 m_check_domtree_version = true; 1116 sendNotifyProgressFinished(); 1117} 1118 1119void WebViewCore::doMaxScroll(CacheBuilder::Direction dir) 1120{ 1121 int dx = 0, dy = 0; 1122 1123 switch (dir) { 1124 case CacheBuilder::LEFT: 1125 dx = -m_maxXScroll; 1126 break; 1127 case CacheBuilder::UP: 1128 dy = -m_maxYScroll; 1129 break; 1130 case CacheBuilder::RIGHT: 1131 dx = m_maxXScroll; 1132 break; 1133 case CacheBuilder::DOWN: 1134 dy = m_maxYScroll; 1135 break; 1136 case CacheBuilder::UNINITIALIZED: 1137 default: 1138 LOG_ASSERT(0, "unexpected focus selector"); 1139 } 1140 WebCore::FrameView* view = m_mainFrame->view(); 1141 this->scrollTo(view->scrollX() + dx, view->scrollY() + dy, true); 1142} 1143 1144void WebViewCore::setScrollOffset(int moveGeneration, bool sendScrollEvent, int dx, int dy) 1145{ 1146 DBG_NAV_LOGD("{%d,%d} m_scrollOffset=(%d,%d), sendScrollEvent=%d", dx, dy, 1147 m_scrollOffsetX, m_scrollOffsetY, sendScrollEvent); 1148 if (m_scrollOffsetX != dx || m_scrollOffsetY != dy) { 1149 m_scrollOffsetX = dx; 1150 m_scrollOffsetY = dy; 1151 // The visible rect is located within our coordinate space so it 1152 // contains the actual scroll position. Setting the location makes hit 1153 // testing work correctly. 1154 m_mainFrame->view()->platformWidget()->setLocation(m_scrollOffsetX, 1155 m_scrollOffsetY); 1156 if (sendScrollEvent) { 1157 m_mainFrame->eventHandler()->sendScrollEvent(); 1158 1159 // Only update history position if it's user scrolled. 1160 // Update history item to reflect the new scroll position. 1161 // This also helps save the history information when the browser goes to 1162 // background, so scroll position will be restored if browser gets 1163 // killed while in background. 1164 WebCore::HistoryController* history = m_mainFrame->loader()->history(); 1165 // Because the history item saving could be heavy for large sites and 1166 // scrolling can generate lots of small scroll offset, the following code 1167 // reduces the saving frequency. 1168 static const int MIN_SCROLL_DIFF = 32; 1169 if (history->currentItem()) { 1170 WebCore::IntPoint currentPoint = history->currentItem()->scrollPoint(); 1171 if (std::abs(currentPoint.x() - dx) >= MIN_SCROLL_DIFF || 1172 std::abs(currentPoint.y() - dy) >= MIN_SCROLL_DIFF) { 1173 history->saveScrollPositionAndViewStateToItem(history->currentItem()); 1174 } 1175 } 1176 } 1177 1178 // update the currently visible screen 1179 sendPluginVisibleScreen(); 1180 } 1181 gCursorBoundsMutex.lock(); 1182 bool hasCursorBounds = m_hasCursorBounds; 1183 Frame* frame = (Frame*) m_cursorFrame; 1184 IntPoint location = m_cursorLocation; 1185 gCursorBoundsMutex.unlock(); 1186 if (!hasCursorBounds) 1187 return; 1188 moveMouseIfLatest(moveGeneration, frame, location.x(), location.y()); 1189} 1190 1191void WebViewCore::setGlobalBounds(int x, int y, int h, int v) 1192{ 1193 DBG_NAV_LOGD("{%d,%d}", x, y); 1194 m_mainFrame->view()->platformWidget()->setWindowBounds(x, y, h, v); 1195} 1196 1197void WebViewCore::setSizeScreenWidthAndScale(int width, int height, 1198 int textWrapWidth, float scale, int screenWidth, int screenHeight, 1199 int anchorX, int anchorY, bool ignoreHeight) 1200{ 1201 WebCoreViewBridge* window = m_mainFrame->view()->platformWidget(); 1202 int ow = window->width(); 1203 int oh = window->height(); 1204 int osw = m_screenWidth; 1205 int osh = m_screenHeight; 1206 int otw = m_textWrapWidth; 1207 float oldScale = m_scale; 1208 DBG_NAV_LOGD("old:(w=%d,h=%d,sw=%d,scale=%g) new:(w=%d,h=%d,sw=%d,scale=%g)", 1209 ow, oh, osw, m_scale, width, height, screenWidth, scale); 1210 m_screenWidth = screenWidth; 1211 m_screenHeight = screenHeight; 1212 m_textWrapWidth = textWrapWidth; 1213 if (scale >= 0) // negative means keep the current scale 1214 m_scale = scale; 1215 m_maxXScroll = screenWidth >> 2; 1216 m_maxYScroll = m_maxXScroll * height / width; 1217 // Don't reflow if the diff is small. 1218 const bool reflow = otw && textWrapWidth && 1219 ((float) abs(otw - textWrapWidth) / textWrapWidth) >= 0.01f; 1220 1221 // When the screen size change, fixed positioned element should be updated. 1222 // This is supposed to be light weighted operation without a full layout. 1223 if (osh != screenHeight || osw != screenWidth) 1224 m_mainFrame->view()->updatePositionedObjects(); 1225 1226 if (ow != width || (!ignoreHeight && oh != height) || reflow) { 1227 WebCore::RenderObject *r = m_mainFrame->contentRenderer(); 1228 DBG_NAV_LOGD("renderer=%p view=(w=%d,h=%d)", r, 1229 screenWidth, screenHeight); 1230 if (r) { 1231 WebCore::IntPoint anchorPoint = WebCore::IntPoint(anchorX, anchorY); 1232 DBG_NAV_LOGD("anchorX=%d anchorY=%d", anchorX, anchorY); 1233 RefPtr<WebCore::Node> node; 1234 WebCore::IntRect bounds; 1235 WebCore::IntPoint offset; 1236 // If the text wrap changed, it is probably zoom change or 1237 // orientation change. Try to keep the anchor at the same place. 1238 if (otw && textWrapWidth && otw != textWrapWidth && 1239 (anchorX != 0 || anchorY != 0)) { 1240 WebCore::HitTestResult hitTestResult = 1241 m_mainFrame->eventHandler()->hitTestResultAtPoint( 1242 anchorPoint, false); 1243 node = hitTestResult.innerNode(); 1244 } 1245 if (node) { 1246 bounds = node->getRect(); 1247 DBG_NAV_LOGD("ob:(x=%d,y=%d,w=%d,h=%d)", 1248 bounds.x(), bounds.y(), bounds.width(), bounds.height()); 1249 // sites like nytimes.com insert a non-standard tag <nyt_text> 1250 // in the html. If it is the HitTestResult, it may have zero 1251 // width and height. In this case, use its parent node. 1252 if (bounds.width() == 0) { 1253 node = node->parentOrHostNode(); 1254 if (node) { 1255 bounds = node->getRect(); 1256 DBG_NAV_LOGD("found a zero width node and use its parent, whose ob:(x=%d,y=%d,w=%d,h=%d)", 1257 bounds.x(), bounds.y(), bounds.width(), bounds.height()); 1258 } 1259 } 1260 } 1261 1262 // Set the size after finding the old anchor point as 1263 // hitTestResultAtPoint causes a layout. 1264 window->setSize(width, height); 1265 window->setVisibleSize(screenWidth, screenHeight); 1266 if (width != screenWidth) { 1267 m_mainFrame->view()->setUseFixedLayout(true); 1268 m_mainFrame->view()->setFixedLayoutSize(IntSize(width, height)); 1269 } else { 1270 m_mainFrame->view()->setUseFixedLayout(false); 1271 } 1272 r->setNeedsLayoutAndPrefWidthsRecalc(); 1273 m_mainFrame->view()->forceLayout(); 1274 1275 // scroll to restore current screen center 1276 if (node) { 1277 const WebCore::IntRect& newBounds = node->getRect(); 1278 DBG_NAV_LOGD("nb:(x=%d,y=%d,w=%d," 1279 "h=%d)", newBounds.x(), newBounds.y(), 1280 newBounds.width(), newBounds.height()); 1281 if ((osw && osh && bounds.width() && bounds.height()) 1282 && (bounds != newBounds)) { 1283 WebCore::FrameView* view = m_mainFrame->view(); 1284 // force left align if width is not changed while height changed. 1285 // the anchorPoint is probably at some white space in the node 1286 // which is affected by text wrap around the screen width. 1287 const bool leftAlign = (otw != textWrapWidth) 1288 && (bounds.width() == newBounds.width()) 1289 && (bounds.height() != newBounds.height()); 1290 const float xPercentInDoc = 1291 leftAlign ? 0.0 : (float) (anchorX - bounds.x()) / bounds.width(); 1292 const float xPercentInView = 1293 leftAlign ? 0.0 : (float) (anchorX - m_scrollOffsetX) / osw; 1294 const float yPercentInDoc = (float) (anchorY - bounds.y()) / bounds.height(); 1295 const float yPercentInView = (float) (anchorY - m_scrollOffsetY) / osh; 1296 showRect(newBounds.x(), newBounds.y(), newBounds.width(), 1297 newBounds.height(), view->contentsWidth(), 1298 view->contentsHeight(), 1299 xPercentInDoc, xPercentInView, 1300 yPercentInDoc, yPercentInView); 1301 } 1302 } 1303 } 1304 } else { 1305 window->setSize(width, height); 1306 window->setVisibleSize(screenWidth, screenHeight); 1307 m_mainFrame->view()->resize(width, height); 1308 if (width != screenWidth) { 1309 m_mainFrame->view()->setUseFixedLayout(true); 1310 m_mainFrame->view()->setFixedLayoutSize(IntSize(width, height)); 1311 } else { 1312 m_mainFrame->view()->setUseFixedLayout(false); 1313 } 1314 } 1315 1316 // update the currently visible screen as perceived by the plugin 1317 sendPluginVisibleScreen(); 1318} 1319 1320void WebViewCore::dumpDomTree(bool useFile) 1321{ 1322#ifdef ANDROID_DOM_LOGGING 1323 if (useFile) 1324 gDomTreeFile = fopen(DOM_TREE_LOG_FILE, "w"); 1325 m_mainFrame->document()->showTreeForThis(); 1326 if (gDomTreeFile) { 1327 fclose(gDomTreeFile); 1328 gDomTreeFile = 0; 1329 } 1330#endif 1331} 1332 1333void WebViewCore::dumpRenderTree(bool useFile) 1334{ 1335#ifdef ANDROID_DOM_LOGGING 1336 WTF::CString renderDump = WebCore::externalRepresentation(m_mainFrame).utf8(); 1337 const char* data = renderDump.data(); 1338 if (useFile) { 1339 gRenderTreeFile = fopen(RENDER_TREE_LOG_FILE, "w"); 1340 DUMP_RENDER_LOGD("%s", data); 1341 fclose(gRenderTreeFile); 1342 gRenderTreeFile = 0; 1343 } else { 1344 // adb log can only output 1024 characters, so write out line by line. 1345 // exclude '\n' as adb log adds it for each output. 1346 int length = renderDump.length(); 1347 for (int i = 0, last = 0; i < length; i++) { 1348 if (data[i] == '\n') { 1349 if (i != last) 1350 DUMP_RENDER_LOGD("%.*s", (i - last), &(data[last])); 1351 last = i + 1; 1352 } 1353 } 1354 } 1355#endif 1356} 1357 1358void WebViewCore::dumpNavTree() 1359{ 1360#if DUMP_NAV_CACHE 1361 cacheBuilder().mDebug.print(); 1362#endif 1363} 1364 1365HTMLElement* WebViewCore::retrieveElement(int x, int y, 1366 const QualifiedName& tagName) 1367{ 1368 HitTestResult hitTestResult = m_mainFrame->eventHandler() 1369 ->hitTestResultAtPoint(IntPoint(x, y), false, false, 1370 DontHitTestScrollbars, HitTestRequest::Active | HitTestRequest::ReadOnly, 1371 IntSize(1, 1)); 1372 if (!hitTestResult.innerNode() || !hitTestResult.innerNode()->inDocument()) { 1373 LOGE("Should not happen: no in document Node found"); 1374 return 0; 1375 } 1376 const ListHashSet<RefPtr<Node> >& list = hitTestResult.rectBasedTestResult(); 1377 if (list.isEmpty()) { 1378 LOGE("Should not happen: no rect-based-test nodes found"); 1379 return 0; 1380 } 1381 Node* node = hitTestResult.innerNode(); 1382 Node* element = node; 1383 while (element && (!element->isElementNode() 1384 || !element->hasTagName(tagName))) { 1385 element = element->parentNode(); 1386 } 1387 DBG_NAV_LOGD("node=%p element=%p x=%d y=%d nodeName=%s tagName=%s", node, 1388 element, x, y, node->nodeName().utf8().data(), 1389 element ? ((Element*) element)->tagName().utf8().data() : "<none>"); 1390 return static_cast<WebCore::HTMLElement*>(element); 1391} 1392 1393HTMLAnchorElement* WebViewCore::retrieveAnchorElement(int x, int y) 1394{ 1395 return static_cast<HTMLAnchorElement*> 1396 (retrieveElement(x, y, HTMLNames::aTag)); 1397} 1398 1399HTMLImageElement* WebViewCore::retrieveImageElement(int x, int y) 1400{ 1401 return static_cast<HTMLImageElement*> 1402 (retrieveElement(x, y, HTMLNames::imgTag)); 1403} 1404 1405WTF::String WebViewCore::retrieveHref(int x, int y) 1406{ 1407 WebCore::HTMLAnchorElement* anchor = retrieveAnchorElement(x, y); 1408 return anchor ? anchor->href() : WTF::String(); 1409} 1410 1411WTF::String WebViewCore::retrieveAnchorText(int x, int y) 1412{ 1413 WebCore::HTMLAnchorElement* anchor = retrieveAnchorElement(x, y); 1414 return anchor ? anchor->text() : WTF::String(); 1415} 1416 1417WTF::String WebViewCore::retrieveImageSource(int x, int y) 1418{ 1419 HTMLImageElement* image = retrieveImageElement(x, y); 1420 return image ? image->src().string() : WTF::String(); 1421} 1422 1423WTF::String WebViewCore::requestLabel(WebCore::Frame* frame, 1424 WebCore::Node* node) 1425{ 1426 if (node && CacheBuilder::validNode(m_mainFrame, frame, node)) { 1427 RefPtr<WebCore::NodeList> list = node->document()->getElementsByTagName("label"); 1428 unsigned length = list->length(); 1429 for (unsigned i = 0; i < length; i++) { 1430 WebCore::HTMLLabelElement* label = static_cast<WebCore::HTMLLabelElement*>( 1431 list->item(i)); 1432 if (label->control() == node) { 1433 Node* node = label; 1434 String result; 1435 while ((node = node->traverseNextNode(label))) { 1436 if (node->isTextNode()) { 1437 Text* textNode = static_cast<Text*>(node); 1438 result += textNode->dataImpl(); 1439 } 1440 } 1441 return result; 1442 } 1443 } 1444 } 1445 return WTF::String(); 1446} 1447 1448static bool isContentEditable(const WebCore::Node* node) 1449{ 1450 if (!node) return false; 1451 return node->document()->frame()->selection()->isContentEditable(); 1452} 1453 1454// Returns true if the node is a textfield, textarea, or contentEditable 1455static bool isTextInput(const WebCore::Node* node) 1456{ 1457 if (isContentEditable(node)) 1458 return true; 1459 if (!node) 1460 return false; 1461 WebCore::RenderObject* renderer = node->renderer(); 1462 return renderer && (renderer->isTextField() || renderer->isTextArea()); 1463} 1464 1465void WebViewCore::revealSelection() 1466{ 1467 WebCore::Node* focus = currentFocus(); 1468 if (!focus) 1469 return; 1470 if (!isTextInput(focus)) 1471 return; 1472 WebCore::Frame* focusedFrame = focus->document()->frame(); 1473 if (!focusedFrame->page()->focusController()->isActive()) 1474 return; 1475 focusedFrame->selection()->revealSelection(ScrollAlignment::alignToEdgeIfNeeded); 1476} 1477 1478void WebViewCore::updateCacheOnNodeChange() 1479{ 1480 gCursorBoundsMutex.lock(); 1481 bool hasCursorBounds = m_hasCursorBounds; 1482 Frame* frame = (Frame*) m_cursorFrame; 1483 Node* node = (Node*) m_cursorNode; 1484 IntRect bounds = m_cursorHitBounds; 1485 gCursorBoundsMutex.unlock(); 1486 if (!hasCursorBounds || !node) 1487 return; 1488 if (CacheBuilder::validNode(m_mainFrame, frame, node)) { 1489 RenderObject* renderer = node->renderer(); 1490 if (renderer && renderer->style()->visibility() != HIDDEN) { 1491 IntRect absBox = renderer->absoluteBoundingBoxRect(); 1492 int globalX, globalY; 1493 CacheBuilder::GetGlobalOffset(frame, &globalX, &globalY); 1494 absBox.move(globalX, globalY); 1495 if (absBox == bounds) 1496 return; 1497 DBG_NAV_LOGD("absBox=(%d,%d,%d,%d) bounds=(%d,%d,%d,%d)", 1498 absBox.x(), absBox.y(), absBox.width(), absBox.height(), 1499 bounds.x(), bounds.y(), bounds.width(), bounds.height()); 1500 } 1501 } 1502 DBG_NAV_LOGD("updateFrameCache node=%p", node); 1503 updateFrameCache(); 1504} 1505 1506void WebViewCore::updateFrameCache() 1507{ 1508 if (!m_frameCacheOutOfDate) { 1509 DBG_NAV_LOG("!m_frameCacheOutOfDate"); 1510 return; 1511 } 1512 1513 // If there is a pending style recalculation, do not update the frame cache. 1514 // Until the recalculation is complete, there may be internal objects that 1515 // are in an inconsistent state (such as font pointers). 1516 // In any event, there's not much point to updating the cache while a style 1517 // recalculation is pending, since it will simply have to be updated again 1518 // once the recalculation is complete. 1519 // TODO: Do we need to reschedule an update for after the style is recalculated? 1520 if (m_mainFrame && m_mainFrame->document() && m_mainFrame->document()->isPendingStyleRecalc()) { 1521 LOGW("updateFrameCache: pending style recalc, ignoring."); 1522 return; 1523 } 1524#ifdef ANDROID_INSTRUMENT 1525 TimeCounterAuto counter(TimeCounter::WebViewCoreBuildNavTimeCounter); 1526#endif 1527 m_frameCacheOutOfDate = false; 1528#if DEBUG_NAV_UI 1529 m_now = SkTime::GetMSecs(); 1530#endif 1531 m_temp = new CachedRoot(); 1532 m_temp->init(m_mainFrame, &m_history); 1533#if USE(ACCELERATED_COMPOSITING) 1534 GraphicsLayerAndroid* graphicsLayer = graphicsRootLayer(); 1535 if (graphicsLayer) 1536 m_temp->setRootLayer(graphicsLayer->contentLayer()); 1537#endif 1538 CacheBuilder& builder = cacheBuilder(); 1539 WebCore::Settings* settings = m_mainFrame->page()->settings(); 1540 builder.allowAllTextDetection(); 1541#ifdef ANDROID_META_SUPPORT 1542 if (settings) { 1543 if (!settings->formatDetectionAddress()) 1544 builder.disallowAddressDetection(); 1545 if (!settings->formatDetectionEmail()) 1546 builder.disallowEmailDetection(); 1547 if (!settings->formatDetectionTelephone()) 1548 builder.disallowPhoneDetection(); 1549 } 1550#endif 1551 builder.buildCache(m_temp); 1552 m_tempPict = new SkPicture(); 1553 recordPicture(m_tempPict); 1554 m_temp->setPicture(m_tempPict); 1555 m_temp->setTextGeneration(m_textGeneration); 1556 WebCoreViewBridge* window = m_mainFrame->view()->platformWidget(); 1557 m_temp->setVisibleRect(WebCore::IntRect(m_scrollOffsetX, 1558 m_scrollOffsetY, window->width(), window->height())); 1559 gFrameCacheMutex.lock(); 1560 delete m_frameCacheKit; 1561 delete m_navPictureKit; 1562 m_frameCacheKit = m_temp; 1563 m_navPictureKit = m_tempPict; 1564 m_updatedFrameCache = true; 1565#if DEBUG_NAV_UI 1566 const CachedNode* cachedFocusNode = m_frameCacheKit->currentFocus(); 1567 DBG_NAV_LOGD("cachedFocusNode=%d (nodePointer=%p)", 1568 cachedFocusNode ? cachedFocusNode->index() : 0, 1569 cachedFocusNode ? cachedFocusNode->nodePointer() : 0); 1570#endif 1571 gFrameCacheMutex.unlock(); 1572} 1573 1574void WebViewCore::updateFrameCacheIfLoading() 1575{ 1576 if (!m_check_domtree_version) 1577 updateFrameCache(); 1578} 1579 1580struct TouchNodeData { 1581 Node* mNode; 1582 IntRect mBounds; 1583}; 1584 1585// get the bounding box of the Node 1586static IntRect getAbsoluteBoundingBox(Node* node) { 1587 IntRect rect; 1588 RenderObject* render = node->renderer(); 1589 if (render->isRenderInline()) 1590 rect = toRenderInline(render)->linesVisualOverflowBoundingBox(); 1591 else if (render->isBox()) 1592 rect = toRenderBox(render)->visualOverflowRect(); 1593 else if (render->isText()) 1594 rect = toRenderText(render)->linesBoundingBox(); 1595 else 1596 LOGE("getAbsoluteBoundingBox failed for node %p, name %s", node, render->renderName()); 1597 FloatPoint absPos = render->localToAbsolute(); 1598 rect.move(absPos.x(), absPos.y()); 1599 return rect; 1600} 1601 1602// get the highlight rectangles for the touch point (x, y) with the slop 1603Vector<IntRect> WebViewCore::getTouchHighlightRects(int x, int y, int slop) 1604{ 1605 Vector<IntRect> rects; 1606 m_mousePos = IntPoint(x - m_scrollOffsetX, y - m_scrollOffsetY); 1607 HitTestResult hitTestResult = m_mainFrame->eventHandler()->hitTestResultAtPoint(IntPoint(x, y), 1608 false, false, DontHitTestScrollbars, HitTestRequest::Active | HitTestRequest::ReadOnly, IntSize(slop, slop)); 1609 if (!hitTestResult.innerNode() || !hitTestResult.innerNode()->inDocument()) { 1610 LOGE("Should not happen: no in document Node found"); 1611 return rects; 1612 } 1613 const ListHashSet<RefPtr<Node> >& list = hitTestResult.rectBasedTestResult(); 1614 if (list.isEmpty()) { 1615 LOGE("Should not happen: no rect-based-test nodes found"); 1616 return rects; 1617 } 1618 Frame* frame = hitTestResult.innerNode()->document()->frame(); 1619 Vector<TouchNodeData> nodeDataList; 1620 ListHashSet<RefPtr<Node> >::const_iterator last = list.end(); 1621 for (ListHashSet<RefPtr<Node> >::const_iterator it = list.begin(); it != last; ++it) { 1622 // TODO: it seems reasonable to not search across the frame. Isn't it? 1623 // if the node is not in the same frame as the innerNode, skip it 1624 if (it->get()->document()->frame() != frame) 1625 continue; 1626 // traverse up the tree to find the first node that needs highlight 1627 bool found = false; 1628 Node* eventNode = it->get(); 1629 while (eventNode) { 1630 RenderObject* render = eventNode->renderer(); 1631 if (render->isBody() || render->isRenderView()) 1632 break; 1633 if (eventNode->supportsFocus() 1634 || eventNode->hasEventListeners(eventNames().clickEvent) 1635 || eventNode->hasEventListeners(eventNames().mousedownEvent) 1636 || eventNode->hasEventListeners(eventNames().mouseupEvent)) { 1637 found = true; 1638 break; 1639 } 1640 // the nodes in the rectBasedTestResult() are ordered based on z-index during hit testing. 1641 // so do not search for the eventNode across explicit z-index border. 1642 // TODO: this is a hard one to call. z-index is quite complicated as its value only 1643 // matters when you compare two RenderLayer in the same hierarchy level. e.g. in 1644 // the following example, "b" is on the top as its z level is the highest. even "c" 1645 // has 100 as z-index, it is still below "d" as its parent has the same z-index as 1646 // "d" and logically before "d". Of course "a" is the lowest in the z level. 1647 // 1648 // z-index:auto "a" 1649 // z-index:2 "b" 1650 // z-index:1 1651 // z-index:100 "c" 1652 // z-index:1 "d" 1653 // 1654 // If the fat point touches everyone, the order in the list should be "b", "d", "c" 1655 // and "a". When we search for the event node for "b", we really don't want "a" as 1656 // in the z-order it is behind everything else. 1657 if (!render->style()->hasAutoZIndex()) 1658 break; 1659 eventNode = eventNode->parentNode(); 1660 } 1661 // didn't find any eventNode, skip it 1662 if (!found) 1663 continue; 1664 // first quick check whether it is a duplicated node before computing bounding box 1665 Vector<TouchNodeData>::const_iterator nlast = nodeDataList.end(); 1666 for (Vector<TouchNodeData>::const_iterator n = nodeDataList.begin(); n != nlast; ++n) { 1667 // found the same node, skip it 1668 if (eventNode == n->mNode) { 1669 found = false; 1670 break; 1671 } 1672 } 1673 if (!found) 1674 continue; 1675 // next check whether the node is fully covered by or fully covering another node. 1676 found = false; 1677 IntRect rect = getAbsoluteBoundingBox(eventNode); 1678 if (rect.isEmpty()) { 1679 // if the node's bounds is empty and it is not a ContainerNode, skip it. 1680 if (!eventNode->isContainerNode()) 1681 continue; 1682 // if the node's children are all positioned objects, its bounds can be empty. 1683 // Walk through the children to find the bounding box. 1684 Node* child = static_cast<const ContainerNode*>(eventNode)->firstChild(); 1685 while (child) { 1686 IntRect childrect; 1687 if (child->renderer()) 1688 childrect = getAbsoluteBoundingBox(child); 1689 if (!childrect.isEmpty()) { 1690 rect.unite(childrect); 1691 child = child->traverseNextSibling(eventNode); 1692 } else 1693 child = child->traverseNextNode(eventNode); 1694 } 1695 } 1696 for (int i = nodeDataList.size() - 1; i >= 0; i--) { 1697 TouchNodeData n = nodeDataList.at(i); 1698 // the new node is enclosing an existing node, skip it 1699 if (rect.contains(n.mBounds)) { 1700 found = true; 1701 break; 1702 } 1703 // the new node is fully inside an existing node, remove the existing node 1704 if (n.mBounds.contains(rect)) 1705 nodeDataList.remove(i); 1706 } 1707 if (!found) { 1708 TouchNodeData newNode; 1709 newNode.mNode = eventNode; 1710 newNode.mBounds = rect; 1711 nodeDataList.append(newNode); 1712 } 1713 } 1714 if (!nodeDataList.size()) 1715 return rects; 1716 // finally select the node with the largest overlap with the fat point 1717 TouchNodeData final; 1718 final.mNode = 0; 1719 IntPoint docPos = frame->view()->windowToContents(m_mousePos); 1720 IntRect testRect(docPos.x() - slop, docPos.y() - slop, 2 * slop + 1, 2 * slop + 1); 1721 int area = 0; 1722 Vector<TouchNodeData>::const_iterator nlast = nodeDataList.end(); 1723 for (Vector<TouchNodeData>::const_iterator n = nodeDataList.begin(); n != nlast; ++n) { 1724 IntRect rect = n->mBounds; 1725 rect.intersect(testRect); 1726 int a = rect.width() * rect.height(); 1727 if (a > area) { 1728 final = *n; 1729 area = a; 1730 } 1731 } 1732 // now get the node's highlight rectangles in the page coordinate system 1733 if (final.mNode) { 1734 IntPoint frameAdjust; 1735 if (frame != m_mainFrame) { 1736 frameAdjust = frame->view()->contentsToWindow(IntPoint()); 1737 frameAdjust.move(m_scrollOffsetX, m_scrollOffsetY); 1738 } 1739 if (final.mNode->isLink()) { 1740 // most of the links are inline instead of box style. So the bounding box is not 1741 // a good representation for the highlights. Get the list of rectangles instead. 1742 RenderObject* render = final.mNode->renderer(); 1743 IntPoint offset = roundedIntPoint(render->localToAbsolute()); 1744 render->absoluteRects(rects, offset.x() + frameAdjust.x(), offset.y() + frameAdjust.y()); 1745 bool inside = false; 1746 int distance = INT_MAX; 1747 int newx = x, newy = y; 1748 int i = rects.size(); 1749 while (i--) { 1750 if (rects[i].isEmpty()) { 1751 rects.remove(i); 1752 continue; 1753 } 1754 // check whether the point (x, y) is inside one of the rectangles. 1755 if (inside) 1756 continue; 1757 if (rects[i].contains(x, y)) { 1758 inside = true; 1759 continue; 1760 } 1761 if (x >= rects[i].x() && x < rects[i].maxX()) { 1762 if (y < rects[i].y()) { 1763 if (rects[i].y() - y < distance) { 1764 newx = x; 1765 newy = rects[i].y(); 1766 distance = rects[i].y() - y; 1767 } 1768 } else if (y >= rects[i].maxY()) { 1769 if (y - rects[i].maxY() + 1 < distance) { 1770 newx = x; 1771 newy = rects[i].maxY() - 1; 1772 distance = y - rects[i].maxY() + 1; 1773 } 1774 } 1775 } else if (y >= rects[i].y() && y < rects[i].maxY()) { 1776 if (x < rects[i].x()) { 1777 if (rects[i].x() - x < distance) { 1778 newx = rects[i].x(); 1779 newy = y; 1780 distance = rects[i].x() - x; 1781 } 1782 } else if (x >= rects[i].maxX()) { 1783 if (x - rects[i].maxX() + 1 < distance) { 1784 newx = rects[i].maxX() - 1; 1785 newy = y; 1786 distance = x - rects[i].maxX() + 1; 1787 } 1788 } 1789 } 1790 } 1791 if (!rects.isEmpty()) { 1792 if (!inside) { 1793 // if neither x nor y has overlap, just pick the top/left of the first rectangle 1794 if (newx == x && newy == y) { 1795 newx = rects[0].x(); 1796 newy = rects[0].y(); 1797 } 1798 m_mousePos.setX(newx - m_scrollOffsetX); 1799 m_mousePos.setY(newy - m_scrollOffsetY); 1800 DBG_NAV_LOGD("Move x/y from (%d, %d) to (%d, %d) scrollOffset is (%d, %d)", 1801 x, y, m_mousePos.x() + m_scrollOffsetX, m_mousePos.y() + m_scrollOffsetY, 1802 m_scrollOffsetX, m_scrollOffsetY); 1803 } 1804 return rects; 1805 } 1806 } 1807 IntRect rect = final.mBounds; 1808 rect.move(frameAdjust.x(), frameAdjust.y()); 1809 rects.append(rect); 1810 // adjust m_mousePos if it is not inside the returned highlight rectangle 1811 testRect.move(frameAdjust.x(), frameAdjust.y()); 1812 testRect.intersect(rect); 1813 if (!testRect.contains(x, y)) { 1814 m_mousePos = testRect.center(); 1815 m_mousePos.move(-m_scrollOffsetX, -m_scrollOffsetY); 1816 DBG_NAV_LOGD("Move x/y from (%d, %d) to (%d, %d) scrollOffset is (%d, %d)", 1817 x, y, m_mousePos.x() + m_scrollOffsetX, m_mousePos.y() + m_scrollOffsetY, 1818 m_scrollOffsetX, m_scrollOffsetY); 1819 } 1820 } 1821 return rects; 1822} 1823 1824/////////////////////////////////////////////////////////////////////////////// 1825 1826void WebViewCore::addPlugin(PluginWidgetAndroid* w) 1827{ 1828// SkDebugf("----------- addPlugin %p", w); 1829 /* The plugin must be appended to the end of the array. This ensures that if 1830 the plugin is added while iterating through the array (e.g. sendEvent(...)) 1831 that the iteration process is not corrupted. 1832 */ 1833 *m_plugins.append() = w; 1834} 1835 1836void WebViewCore::removePlugin(PluginWidgetAndroid* w) 1837{ 1838// SkDebugf("----------- removePlugin %p", w); 1839 int index = m_plugins.find(w); 1840 if (index < 0) { 1841 SkDebugf("--------------- pluginwindow not found! %p\n", w); 1842 } else { 1843 m_plugins.removeShuffle(index); 1844 } 1845} 1846 1847bool WebViewCore::isPlugin(PluginWidgetAndroid* w) const 1848{ 1849 return m_plugins.find(w) >= 0; 1850} 1851 1852void WebViewCore::invalPlugin(PluginWidgetAndroid* w) 1853{ 1854 const double PLUGIN_INVAL_DELAY = 1.0 / 60; 1855 1856 if (!m_pluginInvalTimer.isActive()) { 1857 m_pluginInvalTimer.startOneShot(PLUGIN_INVAL_DELAY); 1858 } 1859} 1860 1861void WebViewCore::drawPlugins() 1862{ 1863 SkRegion inval; // accumualte what needs to be redrawn 1864 PluginWidgetAndroid** iter = m_plugins.begin(); 1865 PluginWidgetAndroid** stop = m_plugins.end(); 1866 1867 for (; iter < stop; ++iter) { 1868 PluginWidgetAndroid* w = *iter; 1869 SkIRect dirty; 1870 if (w->isDirty(&dirty)) { 1871 w->draw(); 1872 inval.op(dirty, SkRegion::kUnion_Op); 1873 } 1874 } 1875 1876 if (!inval.isEmpty()) { 1877 // inval.getBounds() is our rectangle 1878 const SkIRect& bounds = inval.getBounds(); 1879 WebCore::IntRect r(bounds.fLeft, bounds.fTop, 1880 bounds.width(), bounds.height()); 1881 this->viewInvalidate(r); 1882 } 1883} 1884 1885void WebViewCore::notifyPluginsOnFrameLoad(const Frame* frame) { 1886 // if frame is the parent then notify all plugins 1887 if (!frame->tree()->parent()) { 1888 // trigger an event notifying the plugins that the page has loaded 1889 ANPEvent event; 1890 SkANP::InitEvent(&event, kLifecycle_ANPEventType); 1891 event.data.lifecycle.action = kOnLoad_ANPLifecycleAction; 1892 sendPluginEvent(event); 1893 // trigger the on/off screen notification if the page was reloaded 1894 sendPluginVisibleScreen(); 1895 } 1896 // else if frame's parent has completed 1897 else if (!frame->tree()->parent()->loader()->isLoading()) { 1898 // send to all plugins who have this frame in their heirarchy 1899 PluginWidgetAndroid** iter = m_plugins.begin(); 1900 PluginWidgetAndroid** stop = m_plugins.end(); 1901 for (; iter < stop; ++iter) { 1902 Frame* currentFrame = (*iter)->pluginView()->parentFrame(); 1903 while (currentFrame) { 1904 if (frame == currentFrame) { 1905 ANPEvent event; 1906 SkANP::InitEvent(&event, kLifecycle_ANPEventType); 1907 event.data.lifecycle.action = kOnLoad_ANPLifecycleAction; 1908 (*iter)->sendEvent(event); 1909 1910 // trigger the on/off screen notification if the page was reloaded 1911 ANPRectI visibleRect; 1912 getVisibleScreen(visibleRect); 1913 (*iter)->setVisibleScreen(visibleRect, m_scale); 1914 1915 break; 1916 } 1917 currentFrame = currentFrame->tree()->parent(); 1918 } 1919 } 1920 } 1921} 1922 1923void WebViewCore::getVisibleScreen(ANPRectI& visibleRect) 1924{ 1925 visibleRect.left = m_scrollOffsetX; 1926 visibleRect.top = m_scrollOffsetY; 1927 visibleRect.right = m_scrollOffsetX + m_screenWidth; 1928 visibleRect.bottom = m_scrollOffsetY + m_screenHeight; 1929} 1930 1931void WebViewCore::sendPluginVisibleScreen() 1932{ 1933 /* We may want to cache the previous values and only send the notification 1934 to the plugin in the event that one of the values has changed. 1935 */ 1936 1937 ANPRectI visibleRect; 1938 getVisibleScreen(visibleRect); 1939 1940 PluginWidgetAndroid** iter = m_plugins.begin(); 1941 PluginWidgetAndroid** stop = m_plugins.end(); 1942 for (; iter < stop; ++iter) { 1943 (*iter)->setVisibleScreen(visibleRect, m_scale); 1944 } 1945} 1946 1947void WebViewCore::sendPluginEvent(const ANPEvent& evt) 1948{ 1949 /* The list of plugins may be manipulated as we iterate through the list. 1950 This implementation allows for the addition of new plugins during an 1951 iteration, but may fail if a plugin is removed. Currently, there are not 1952 any use cases where a plugin is deleted while processing this loop, but 1953 if it does occur we will have to use an alternate data structure and/or 1954 iteration mechanism. 1955 */ 1956 for (int x = 0; x < m_plugins.count(); x++) { 1957 m_plugins[x]->sendEvent(evt); 1958 } 1959} 1960 1961PluginWidgetAndroid* WebViewCore::getPluginWidget(NPP npp) 1962{ 1963 PluginWidgetAndroid** iter = m_plugins.begin(); 1964 PluginWidgetAndroid** stop = m_plugins.end(); 1965 for (; iter < stop; ++iter) { 1966 if ((*iter)->pluginView()->instance() == npp) { 1967 return (*iter); 1968 } 1969 } 1970 return 0; 1971} 1972 1973static PluginView* nodeIsPlugin(Node* node) { 1974 RenderObject* renderer = node->renderer(); 1975 if (renderer && renderer->isWidget()) { 1976 Widget* widget = static_cast<RenderWidget*>(renderer)->widget(); 1977 if (widget && widget->isPluginView()) 1978 return static_cast<PluginView*>(widget); 1979 } 1980 return 0; 1981} 1982 1983Node* WebViewCore::cursorNodeIsPlugin() { 1984 gCursorBoundsMutex.lock(); 1985 bool hasCursorBounds = m_hasCursorBounds; 1986 Frame* frame = (Frame*) m_cursorFrame; 1987 Node* node = (Node*) m_cursorNode; 1988 gCursorBoundsMutex.unlock(); 1989 if (hasCursorBounds && CacheBuilder::validNode(m_mainFrame, frame, node) 1990 && nodeIsPlugin(node)) { 1991 return node; 1992 } 1993 return 0; 1994} 1995 1996/////////////////////////////////////////////////////////////////////////////// 1997void WebViewCore::moveMouseIfLatest(int moveGeneration, 1998 WebCore::Frame* frame, int x, int y) 1999{ 2000 DBG_NAV_LOGD("m_moveGeneration=%d moveGeneration=%d" 2001 " frame=%p x=%d y=%d", 2002 m_moveGeneration, moveGeneration, frame, x, y); 2003 if (m_moveGeneration > moveGeneration) { 2004 DBG_NAV_LOGD("m_moveGeneration=%d > moveGeneration=%d", 2005 m_moveGeneration, moveGeneration); 2006 return; // short-circuit if a newer move has already been generated 2007 } 2008 m_lastGeneration = moveGeneration; 2009 moveMouse(frame, x, y); 2010} 2011 2012void WebViewCore::moveFocus(WebCore::Frame* frame, WebCore::Node* node) 2013{ 2014 DBG_NAV_LOGD("frame=%p node=%p", frame, node); 2015 if (!node || !CacheBuilder::validNode(m_mainFrame, frame, node) 2016 || !node->isElementNode()) 2017 return; 2018 // Code borrowed from FocusController::advanceFocus 2019 WebCore::FocusController* focusController 2020 = m_mainFrame->page()->focusController(); 2021 WebCore::Document* oldDoc 2022 = focusController->focusedOrMainFrame()->document(); 2023 if (oldDoc->focusedNode() == node) 2024 return; 2025 if (node->document() != oldDoc) 2026 oldDoc->setFocusedNode(0); 2027 focusController->setFocusedFrame(frame); 2028 static_cast<WebCore::Element*>(node)->focus(false); 2029} 2030 2031// Update mouse position 2032void WebViewCore::moveMouse(WebCore::Frame* frame, int x, int y) 2033{ 2034 DBG_NAV_LOGD("frame=%p x=%d y=%d scrollOffset=(%d,%d)", frame, 2035 x, y, m_scrollOffsetX, m_scrollOffsetY); 2036 if (!frame || !CacheBuilder::validNode(m_mainFrame, frame, 0)) 2037 frame = m_mainFrame; 2038 // mouse event expects the position in the window coordinate 2039 m_mousePos = WebCore::IntPoint(x - m_scrollOffsetX, y - m_scrollOffsetY); 2040 // validNode will still return true if the node is null, as long as we have 2041 // a valid frame. Do not want to make a call on frame unless it is valid. 2042 WebCore::PlatformMouseEvent mouseEvent(m_mousePos, m_mousePos, 2043 WebCore::NoButton, WebCore::MouseEventMoved, 1, false, false, false, 2044 false, WTF::currentTime()); 2045 frame->eventHandler()->handleMouseMoveEvent(mouseEvent); 2046 updateCacheOnNodeChange(); 2047} 2048 2049void WebViewCore::setSelection(int start, int end) 2050{ 2051 WebCore::Node* focus = currentFocus(); 2052 if (!focus) 2053 return; 2054 WebCore::RenderObject* renderer = focus->renderer(); 2055 if (!renderer || (!renderer->isTextField() && !renderer->isTextArea())) 2056 return; 2057 if (start > end) { 2058 int temp = start; 2059 start = end; 2060 end = temp; 2061 } 2062 // Tell our EditorClient that this change was generated from the UI, so it 2063 // does not need to echo it to the UI. 2064 EditorClientAndroid* client = static_cast<EditorClientAndroid*>( 2065 m_mainFrame->editor()->client()); 2066 client->setUiGeneratedSelectionChange(true); 2067 setSelectionRange(focus, start, end); 2068 client->setUiGeneratedSelectionChange(false); 2069 WebCore::Frame* focusedFrame = focus->document()->frame(); 2070 bool isPasswordField = false; 2071 if (focus->isElementNode()) { 2072 WebCore::Element* element = static_cast<WebCore::Element*>(focus); 2073 if (WebCore::InputElement* inputElement = WebCore::toInputElement(element)) 2074 isPasswordField = static_cast<WebCore::HTMLInputElement*>(inputElement)->isPasswordField(); 2075 } 2076 // For password fields, this is done in the UI side via 2077 // bringPointIntoView, since the UI does the drawing. 2078 if (renderer->isTextArea() || !isPasswordField) 2079 revealSelection(); 2080} 2081 2082String WebViewCore::modifySelection(const int direction, const int axis) 2083{ 2084 DOMSelection* selection = m_mainFrame->domWindow()->getSelection(); 2085 if (selection->rangeCount() > 1) 2086 selection->removeAllRanges(); 2087 switch (axis) { 2088 case AXIS_CHARACTER: 2089 case AXIS_WORD: 2090 case AXIS_SENTENCE: 2091 return modifySelectionTextNavigationAxis(selection, direction, axis); 2092 case AXIS_HEADING: 2093 case AXIS_SIBLING: 2094 case AXIS_PARENT_FIRST_CHILD: 2095 case AXIS_DOCUMENT: 2096 return modifySelectionDomNavigationAxis(selection, direction, axis); 2097 default: 2098 LOGE("Invalid navigation axis: %d", axis); 2099 return String(); 2100 } 2101} 2102 2103void WebViewCore::scrollNodeIntoView(Frame* frame, Node* node) 2104{ 2105 if (!frame || !node) 2106 return; 2107 2108 Element* elementNode = 0; 2109 2110 // If not an Element, find a visible predecessor 2111 // Element to scroll into view. 2112 if (!node->isElementNode()) { 2113 HTMLElement* body = frame->document()->body(); 2114 do { 2115 if (!node || node == body) 2116 return; 2117 node = node->parentNode(); 2118 } while (!node->isElementNode() && !isVisible(node)); 2119 } 2120 2121 elementNode = static_cast<Element*>(node); 2122 elementNode->scrollIntoViewIfNeeded(true); 2123} 2124 2125String WebViewCore::modifySelectionTextNavigationAxis(DOMSelection* selection, int direction, int axis) 2126{ 2127 Node* body = m_mainFrame->document()->body(); 2128 2129 ExceptionCode ec = 0; 2130 String markup; 2131 2132 // initialize the selection if necessary 2133 if (selection->rangeCount() == 0) { 2134 if (m_currentNodeDomNavigationAxis 2135 && CacheBuilder::validNode(m_mainFrame, 2136 m_mainFrame, m_currentNodeDomNavigationAxis)) { 2137 PassRefPtr<Range> rangeRef = 2138 selection->frame()->document()->createRange(); 2139 rangeRef->selectNode(m_currentNodeDomNavigationAxis, ec); 2140 m_currentNodeDomNavigationAxis = 0; 2141 if (ec) 2142 return String(); 2143 selection->addRange(rangeRef.get()); 2144 } else if (currentFocus()) { 2145 selection->setPosition(currentFocus(), 0, ec); 2146 } else if (m_cursorNode 2147 && CacheBuilder::validNode(m_mainFrame, 2148 m_mainFrame, m_cursorNode)) { 2149 PassRefPtr<Range> rangeRef = 2150 selection->frame()->document()->createRange(); 2151 rangeRef->selectNode(reinterpret_cast<Node*>(m_cursorNode), ec); 2152 if (ec) 2153 return String(); 2154 selection->addRange(rangeRef.get()); 2155 } else { 2156 selection->setPosition(body, 0, ec); 2157 } 2158 if (ec) 2159 return String(); 2160 } 2161 2162 // collapse the selection 2163 if (direction == DIRECTION_FORWARD) 2164 selection->collapseToEnd(ec); 2165 else 2166 selection->collapseToStart(ec); 2167 if (ec) 2168 return String(); 2169 2170 // Make sure the anchor node is a text node since we are generating 2171 // the markup of the selection which includes the anchor, the focus, 2172 // and any crossed nodes. Forcing the condition that the selection 2173 // starts and ends on text nodes guarantees symmetric selection markup. 2174 // Also this way the text content, rather its container, is highlighted. 2175 Node* anchorNode = selection->anchorNode(); 2176 if (anchorNode->isElementNode()) { 2177 // Collapsed selection while moving forward points to the 2178 // next unvisited node and while moving backward to the 2179 // last visited node. 2180 if (direction == DIRECTION_FORWARD) 2181 advanceAnchorNode(selection, direction, markup, false, ec); 2182 else 2183 advanceAnchorNode(selection, direction, markup, true, ec); 2184 if (ec) 2185 return String(); 2186 if (!markup.isEmpty()) 2187 return markup; 2188 } 2189 2190 // If the selection is at the end of a non white space text move 2191 // it to the next visible text node with non white space content. 2192 // This is a workaround for the selection getting stuck. 2193 anchorNode = selection->anchorNode(); 2194 if (anchorNode->isTextNode()) { 2195 if (direction == DIRECTION_FORWARD) { 2196 String suffix = anchorNode->textContent().substring( 2197 selection->anchorOffset(), caretMaxOffset(anchorNode)); 2198 // If at the end of non white space text we advance the 2199 // anchor node to either an input element or non empty text. 2200 if (suffix.stripWhiteSpace().isEmpty()) { 2201 advanceAnchorNode(selection, direction, markup, true, ec); 2202 } 2203 } else { 2204 String prefix = anchorNode->textContent().substring(0, 2205 selection->anchorOffset()); 2206 // If at the end of non white space text we advance the 2207 // anchor node to either an input element or non empty text. 2208 if (prefix.stripWhiteSpace().isEmpty()) { 2209 advanceAnchorNode(selection, direction, markup, true, ec); 2210 } 2211 } 2212 if (ec) 2213 return String(); 2214 if (!markup.isEmpty()) 2215 return markup; 2216 } 2217 2218 // extend the selection 2219 String directionStr; 2220 if (direction == DIRECTION_FORWARD) 2221 directionStr = "forward"; 2222 else 2223 directionStr = "backward"; 2224 2225 String axisStr; 2226 if (axis == AXIS_CHARACTER) 2227 axisStr = "character"; 2228 else if (axis == AXIS_WORD) 2229 axisStr = "word"; 2230 else 2231 axisStr = "sentence"; 2232 2233 selection->modify("extend", directionStr, axisStr); 2234 2235 // Make sure the focus node is a text node in order to have the 2236 // selection generate symmetric markup because the latter 2237 // includes all nodes crossed by the selection. Also this way 2238 // the text content, rather its container, is highlighted. 2239 Node* focusNode = selection->focusNode(); 2240 if (focusNode->isElementNode()) { 2241 focusNode = getImplicitBoundaryNode(selection->focusNode(), 2242 selection->focusOffset(), direction); 2243 if (!focusNode) 2244 return String(); 2245 if (direction == DIRECTION_FORWARD) { 2246 focusNode = focusNode->traversePreviousSiblingPostOrder(body); 2247 if (focusNode && !isContentTextNode(focusNode)) { 2248 Node* textNode = traverseNextContentTextNode(focusNode, 2249 anchorNode, DIRECTION_BACKWARD); 2250 if (textNode) 2251 anchorNode = textNode; 2252 } 2253 if (focusNode && isContentTextNode(focusNode)) { 2254 selection->extend(focusNode, caretMaxOffset(focusNode), ec); 2255 if (ec) 2256 return String(); 2257 } 2258 } else { 2259 focusNode = focusNode->traverseNextSibling(); 2260 if (focusNode && !isContentTextNode(focusNode)) { 2261 Node* textNode = traverseNextContentTextNode(focusNode, 2262 anchorNode, DIRECTION_FORWARD); 2263 if (textNode) 2264 anchorNode = textNode; 2265 } 2266 if (anchorNode && isContentTextNode(anchorNode)) { 2267 selection->extend(focusNode, 0, ec); 2268 if (ec) 2269 return String(); 2270 } 2271 } 2272 } 2273 2274 // Enforce that the selection does not cross anchor boundaries. This is 2275 // a workaround for the asymmetric behavior of WebKit while crossing 2276 // anchors. 2277 anchorNode = getImplicitBoundaryNode(selection->anchorNode(), 2278 selection->anchorOffset(), direction); 2279 focusNode = getImplicitBoundaryNode(selection->focusNode(), 2280 selection->focusOffset(), direction); 2281 if (anchorNode && focusNode && anchorNode != focusNode) { 2282 Node* inputControl = getIntermediaryInputElement(anchorNode, focusNode, 2283 direction); 2284 if (inputControl) { 2285 if (direction == DIRECTION_FORWARD) { 2286 if (isDescendantOf(inputControl, anchorNode)) { 2287 focusNode = inputControl; 2288 } else { 2289 focusNode = inputControl->traversePreviousSiblingPostOrder( 2290 body); 2291 if (!focusNode) 2292 focusNode = inputControl; 2293 } 2294 // We prefer a text node contained in the input element. 2295 if (!isContentTextNode(focusNode)) { 2296 Node* textNode = traverseNextContentTextNode(focusNode, 2297 anchorNode, DIRECTION_BACKWARD); 2298 if (textNode) 2299 focusNode = textNode; 2300 } 2301 // If we found text in the input select it. 2302 // Otherwise, select the input element itself. 2303 if (isContentTextNode(focusNode)) { 2304 selection->extend(focusNode, caretMaxOffset(focusNode), ec); 2305 } else if (anchorNode != focusNode) { 2306 // Note that the focusNode always has parent and that 2307 // the offset can be one more that the index of the last 2308 // element - this is how WebKit selects such elements. 2309 selection->extend(focusNode->parentNode(), 2310 focusNode->nodeIndex() + 1, ec); 2311 } 2312 if (ec) 2313 return String(); 2314 } else { 2315 if (isDescendantOf(inputControl, anchorNode)) { 2316 focusNode = inputControl; 2317 } else { 2318 focusNode = inputControl->traverseNextSibling(); 2319 if (!focusNode) 2320 focusNode = inputControl; 2321 } 2322 // We prefer a text node contained in the input element. 2323 if (!isContentTextNode(focusNode)) { 2324 Node* textNode = traverseNextContentTextNode(focusNode, 2325 anchorNode, DIRECTION_FORWARD); 2326 if (textNode) 2327 focusNode = textNode; 2328 } 2329 // If we found text in the input select it. 2330 // Otherwise, select the input element itself. 2331 if (isContentTextNode(focusNode)) { 2332 selection->extend(focusNode, caretMinOffset(focusNode), ec); 2333 } else if (anchorNode != focusNode) { 2334 // Note that the focusNode always has parent and that 2335 // the offset can be one more that the index of the last 2336 // element - this is how WebKit selects such elements. 2337 selection->extend(focusNode->parentNode(), 2338 focusNode->nodeIndex() + 1, ec); 2339 } 2340 if (ec) 2341 return String(); 2342 } 2343 } 2344 } 2345 2346 // make sure the selection is visible 2347 if (direction == DIRECTION_FORWARD) 2348 scrollNodeIntoView(m_mainFrame, selection->focusNode()); 2349 else 2350 scrollNodeIntoView(m_mainFrame, selection->anchorNode()); 2351 2352 // format markup for the visible content 2353 PassRefPtr<Range> range = selection->getRangeAt(0, ec); 2354 if (ec) 2355 return String(); 2356 IntRect bounds = range->boundingBox(); 2357 selectAt(bounds.center().x(), bounds.center().y()); 2358 markup = formatMarkup(selection); 2359 LOGV("Selection markup: %s", markup.utf8().data()); 2360 2361 return markup; 2362} 2363 2364Node* WebViewCore::getImplicitBoundaryNode(Node* node, unsigned offset, int direction) 2365{ 2366 if (node->offsetInCharacters()) 2367 return node; 2368 if (!node->hasChildNodes()) 2369 return node; 2370 if (offset < node->childNodeCount()) 2371 return node->childNode(offset); 2372 else 2373 if (direction == DIRECTION_FORWARD) 2374 return node->traverseNextSibling(); 2375 else 2376 return node->traversePreviousNodePostOrder( 2377 node->document()->body()); 2378} 2379 2380Node* WebViewCore::getNextAnchorNode(Node* anchorNode, bool ignoreFirstNode, int direction) 2381{ 2382 Node* body = 0; 2383 Node* currentNode = 0; 2384 if (direction == DIRECTION_FORWARD) { 2385 if (ignoreFirstNode) 2386 currentNode = anchorNode->traverseNextNode(body); 2387 else 2388 currentNode = anchorNode; 2389 } else { 2390 body = anchorNode->document()->body(); 2391 if (ignoreFirstNode) 2392 currentNode = anchorNode->traversePreviousSiblingPostOrder(body); 2393 else 2394 currentNode = anchorNode; 2395 } 2396 while (currentNode) { 2397 if (isContentTextNode(currentNode) 2398 || isContentInputElement(currentNode)) 2399 return currentNode; 2400 if (direction == DIRECTION_FORWARD) 2401 currentNode = currentNode->traverseNextNode(); 2402 else 2403 currentNode = currentNode->traversePreviousNodePostOrder(body); 2404 } 2405 return 0; 2406} 2407 2408void WebViewCore::advanceAnchorNode(DOMSelection* selection, int direction, 2409 String& markup, bool ignoreFirstNode, ExceptionCode& ec) 2410{ 2411 Node* anchorNode = getImplicitBoundaryNode(selection->anchorNode(), 2412 selection->anchorOffset(), direction); 2413 if (!anchorNode) { 2414 ec = NOT_FOUND_ERR; 2415 return; 2416 } 2417 // If the anchor offset is invalid i.e. the anchor node has no 2418 // child with that index getImplicitAnchorNode returns the next 2419 // logical node in the current direction. In such a case our 2420 // position in the DOM tree was has already been advanced, 2421 // therefore we there is no need to do that again. 2422 if (selection->anchorNode()->isElementNode()) { 2423 unsigned anchorOffset = selection->anchorOffset(); 2424 unsigned childNodeCount = selection->anchorNode()->childNodeCount(); 2425 if (anchorOffset >= childNodeCount) 2426 ignoreFirstNode = false; 2427 } 2428 // Find the next anchor node given our position in the DOM and 2429 // whether we want the current node to be considered as well. 2430 Node* nextAnchorNode = getNextAnchorNode(anchorNode, ignoreFirstNode, 2431 direction); 2432 if (!nextAnchorNode) { 2433 ec = NOT_FOUND_ERR; 2434 return; 2435 } 2436 if (nextAnchorNode->isElementNode()) { 2437 // If this is an input element tell the WebView thread 2438 // to set the cursor to that control. 2439 if (isContentInputElement(nextAnchorNode)) { 2440 IntRect bounds = nextAnchorNode->getRect(); 2441 selectAt(bounds.center().x(), bounds.center().y()); 2442 } 2443 Node* textNode = 0; 2444 // Treat the text content of links as any other text but 2445 // for the rest input elements select the control itself. 2446 if (nextAnchorNode->hasTagName(WebCore::HTMLNames::aTag)) 2447 textNode = traverseNextContentTextNode(nextAnchorNode, 2448 nextAnchorNode, direction); 2449 // We prefer to select the text content of the link if such, 2450 // otherwise just select the element itself. 2451 if (textNode) { 2452 nextAnchorNode = textNode; 2453 } else { 2454 if (direction == DIRECTION_FORWARD) { 2455 selection->setBaseAndExtent(nextAnchorNode, 2456 caretMinOffset(nextAnchorNode), nextAnchorNode, 2457 caretMaxOffset(nextAnchorNode), ec); 2458 } else { 2459 selection->setBaseAndExtent(nextAnchorNode, 2460 caretMaxOffset(nextAnchorNode), nextAnchorNode, 2461 caretMinOffset(nextAnchorNode), ec); 2462 } 2463 if (!ec) 2464 markup = formatMarkup(selection); 2465 // make sure the selection is visible 2466 scrollNodeIntoView(selection->frame(), nextAnchorNode); 2467 return; 2468 } 2469 } 2470 if (direction == DIRECTION_FORWARD) 2471 selection->setPosition(nextAnchorNode, 2472 caretMinOffset(nextAnchorNode), ec); 2473 else 2474 selection->setPosition(nextAnchorNode, 2475 caretMaxOffset(nextAnchorNode), ec); 2476} 2477 2478bool WebViewCore::isContentInputElement(Node* node) 2479{ 2480 return (isVisible(node) 2481 && (node->hasTagName(WebCore::HTMLNames::selectTag) 2482 || node->hasTagName(WebCore::HTMLNames::aTag) 2483 || node->hasTagName(WebCore::HTMLNames::inputTag) 2484 || node->hasTagName(WebCore::HTMLNames::buttonTag))); 2485} 2486 2487bool WebViewCore::isContentTextNode(Node* node) 2488{ 2489 if (!node || !node->isTextNode()) 2490 return false; 2491 Text* textNode = static_cast<Text*>(node); 2492 return (isVisible(textNode) && textNode->length() > 0 2493 && !textNode->containsOnlyWhitespace()); 2494} 2495 2496Text* WebViewCore::traverseNextContentTextNode(Node* fromNode, Node* toNode, int direction) 2497{ 2498 Node* currentNode = fromNode; 2499 do { 2500 if (direction == DIRECTION_FORWARD) 2501 currentNode = currentNode->traverseNextNode(toNode); 2502 else 2503 currentNode = currentNode->traversePreviousNodePostOrder(toNode); 2504 } while (currentNode && !isContentTextNode(currentNode)); 2505 return static_cast<Text*>(currentNode); 2506} 2507 2508Node* WebViewCore::getIntermediaryInputElement(Node* fromNode, Node* toNode, int direction) 2509{ 2510 if (fromNode == toNode) 2511 return 0; 2512 if (direction == DIRECTION_FORWARD) { 2513 Node* currentNode = fromNode; 2514 while (currentNode && currentNode != toNode) { 2515 if (isContentInputElement(currentNode)) 2516 return currentNode; 2517 currentNode = currentNode->traverseNextNodePostOrder(); 2518 } 2519 currentNode = fromNode; 2520 while (currentNode && currentNode != toNode) { 2521 if (isContentInputElement(currentNode)) 2522 return currentNode; 2523 currentNode = currentNode->traverseNextNode(); 2524 } 2525 } else { 2526 Node* currentNode = fromNode->traversePreviousNode(); 2527 while (currentNode && currentNode != toNode) { 2528 if (isContentInputElement(currentNode)) 2529 return currentNode; 2530 currentNode = currentNode->traversePreviousNode(); 2531 } 2532 currentNode = fromNode->traversePreviousNodePostOrder(); 2533 while (currentNode && currentNode != toNode) { 2534 if (isContentInputElement(currentNode)) 2535 return currentNode; 2536 currentNode = currentNode->traversePreviousNodePostOrder(); 2537 } 2538 } 2539 return 0; 2540} 2541 2542bool WebViewCore::isDescendantOf(Node* parent, Node* node) 2543{ 2544 Node* currentNode = node; 2545 while (currentNode) { 2546 if (currentNode == parent) { 2547 return true; 2548 } 2549 currentNode = currentNode->parentNode(); 2550 } 2551 return false; 2552} 2553 2554String WebViewCore::modifySelectionDomNavigationAxis(DOMSelection* selection, int direction, int axis) 2555{ 2556 HTMLElement* body = m_mainFrame->document()->body(); 2557 if (!m_currentNodeDomNavigationAxis && selection->focusNode()) { 2558 m_currentNodeDomNavigationAxis = selection->focusNode(); 2559 selection->empty(); 2560 if (m_currentNodeDomNavigationAxis->isTextNode()) 2561 m_currentNodeDomNavigationAxis = 2562 m_currentNodeDomNavigationAxis->parentNode(); 2563 } 2564 if (!m_currentNodeDomNavigationAxis) 2565 m_currentNodeDomNavigationAxis = currentFocus(); 2566 if (!m_currentNodeDomNavigationAxis 2567 || !CacheBuilder::validNode(m_mainFrame, m_mainFrame, 2568 m_currentNodeDomNavigationAxis)) 2569 m_currentNodeDomNavigationAxis = body; 2570 Node* currentNode = m_currentNodeDomNavigationAxis; 2571 if (axis == AXIS_HEADING) { 2572 if (currentNode == body && direction == DIRECTION_BACKWARD) 2573 currentNode = currentNode->lastDescendant(); 2574 do { 2575 if (direction == DIRECTION_FORWARD) 2576 currentNode = currentNode->traverseNextNode(body); 2577 else 2578 currentNode = currentNode->traversePreviousNode(body); 2579 } while (currentNode && (currentNode->isTextNode() 2580 || !isVisible(currentNode) || !isHeading(currentNode))); 2581 } else if (axis == AXIS_PARENT_FIRST_CHILD) { 2582 if (direction == DIRECTION_FORWARD) { 2583 currentNode = currentNode->firstChild(); 2584 while (currentNode && (currentNode->isTextNode() 2585 || !isVisible(currentNode))) 2586 currentNode = currentNode->nextSibling(); 2587 } else { 2588 do { 2589 if (currentNode == body) 2590 return String(); 2591 currentNode = currentNode->parentNode(); 2592 } while (currentNode && (currentNode->isTextNode() 2593 || !isVisible(currentNode))); 2594 } 2595 } else if (axis == AXIS_SIBLING) { 2596 do { 2597 if (direction == DIRECTION_FORWARD) 2598 currentNode = currentNode->nextSibling(); 2599 else { 2600 if (currentNode == body) 2601 return String(); 2602 currentNode = currentNode->previousSibling(); 2603 } 2604 } while (currentNode && (currentNode->isTextNode() 2605 || !isVisible(currentNode))); 2606 } else if (axis == AXIS_DOCUMENT) { 2607 currentNode = body; 2608 if (direction == DIRECTION_FORWARD) 2609 currentNode = currentNode->lastDescendant(); 2610 } else { 2611 LOGE("Invalid axis: %d", axis); 2612 return String(); 2613 } 2614 if (currentNode) { 2615 m_currentNodeDomNavigationAxis = currentNode; 2616 scrollNodeIntoView(m_mainFrame, currentNode); 2617 String selectionString = createMarkup(currentNode); 2618 LOGV("Selection markup: %s", selectionString.utf8().data()); 2619 return selectionString; 2620 } 2621 return String(); 2622} 2623 2624bool WebViewCore::isHeading(Node* node) 2625{ 2626 if (node->hasTagName(WebCore::HTMLNames::h1Tag) 2627 || node->hasTagName(WebCore::HTMLNames::h2Tag) 2628 || node->hasTagName(WebCore::HTMLNames::h3Tag) 2629 || node->hasTagName(WebCore::HTMLNames::h4Tag) 2630 || node->hasTagName(WebCore::HTMLNames::h5Tag) 2631 || node->hasTagName(WebCore::HTMLNames::h6Tag)) { 2632 return true; 2633 } 2634 2635 if (node->isElementNode()) { 2636 Element* element = static_cast<Element*>(node); 2637 String roleAttribute = 2638 element->getAttribute(WebCore::HTMLNames::roleAttr).string(); 2639 if (equalIgnoringCase(roleAttribute, "heading")) 2640 return true; 2641 } 2642 2643 return false; 2644} 2645 2646bool WebViewCore::isVisible(Node* node) 2647{ 2648 // start off an element 2649 Element* element = 0; 2650 if (node->isElementNode()) 2651 element = static_cast<Element*>(node); 2652 else 2653 element = node->parentElement(); 2654 // check renderer 2655 if (!element->renderer()) { 2656 return false; 2657 } 2658 // check size 2659 if (element->offsetHeight() == 0 || element->offsetWidth() == 0) { 2660 return false; 2661 } 2662 // check style 2663 Node* body = m_mainFrame->document()->body(); 2664 Node* currentNode = element; 2665 while (currentNode && currentNode != body) { 2666 RenderStyle* style = currentNode->computedStyle(); 2667 if (style && 2668 (style->display() == NONE || style->visibility() == HIDDEN)) { 2669 return false; 2670 } 2671 currentNode = currentNode->parentNode(); 2672 } 2673 return true; 2674} 2675 2676String WebViewCore::formatMarkup(DOMSelection* selection) 2677{ 2678 ExceptionCode ec = 0; 2679 String markup = String(); 2680 PassRefPtr<Range> wholeRange = selection->getRangeAt(0, ec); 2681 if (ec) 2682 return String(); 2683 if (!wholeRange->startContainer() || !wholeRange->startContainer()) 2684 return String(); 2685 // Since formatted markup contains invisible nodes it 2686 // is created from the concatenation of the visible fragments. 2687 Node* firstNode = wholeRange->firstNode(); 2688 Node* pastLastNode = wholeRange->pastLastNode(); 2689 Node* currentNode = firstNode; 2690 PassRefPtr<Range> currentRange; 2691 2692 while (currentNode != pastLastNode) { 2693 Node* nextNode = currentNode->traverseNextNode(); 2694 if (!isVisible(currentNode)) { 2695 if (currentRange) { 2696 markup = markup + currentRange->toHTML().utf8().data(); 2697 currentRange = 0; 2698 } 2699 } else { 2700 if (!currentRange) { 2701 currentRange = selection->frame()->document()->createRange(); 2702 if (ec) 2703 break; 2704 if (currentNode == firstNode) { 2705 currentRange->setStart(wholeRange->startContainer(), 2706 wholeRange->startOffset(), ec); 2707 if (ec) 2708 break; 2709 } else { 2710 currentRange->setStart(currentNode->parentNode(), 2711 currentNode->nodeIndex(), ec); 2712 if (ec) 2713 break; 2714 } 2715 } 2716 if (nextNode == pastLastNode) { 2717 currentRange->setEnd(wholeRange->endContainer(), 2718 wholeRange->endOffset(), ec); 2719 if (ec) 2720 break; 2721 markup = markup + currentRange->toHTML().utf8().data(); 2722 } else { 2723 if (currentNode->offsetInCharacters()) 2724 currentRange->setEnd(currentNode, 2725 currentNode->maxCharacterOffset(), ec); 2726 else 2727 currentRange->setEnd(currentNode->parentNode(), 2728 currentNode->nodeIndex() + 1, ec); 2729 if (ec) 2730 break; 2731 } 2732 } 2733 currentNode = nextNode; 2734 } 2735 return markup.stripWhiteSpace(); 2736} 2737 2738void WebViewCore::selectAt(int x, int y) 2739{ 2740 JNIEnv* env = JSC::Bindings::getJNIEnv(); 2741 env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_selectAt, 2742 x, y); 2743 checkException(env); 2744} 2745 2746void WebViewCore::deleteSelection(int start, int end, int textGeneration) 2747{ 2748 setSelection(start, end); 2749 if (start == end) 2750 return; 2751 WebCore::Node* focus = currentFocus(); 2752 if (!focus) 2753 return; 2754 // Prevent our editor client from passing a message to change the 2755 // selection. 2756 EditorClientAndroid* client = static_cast<EditorClientAndroid*>( 2757 m_mainFrame->editor()->client()); 2758 client->setUiGeneratedSelectionChange(true); 2759 PlatformKeyboardEvent down(AKEYCODE_DEL, 0, 0, true, false, false, false); 2760 PlatformKeyboardEvent up(AKEYCODE_DEL, 0, 0, false, false, false, false); 2761 key(down); 2762 key(up); 2763 client->setUiGeneratedSelectionChange(false); 2764 m_textGeneration = textGeneration; 2765 m_shouldPaintCaret = true; 2766} 2767 2768void WebViewCore::replaceTextfieldText(int oldStart, 2769 int oldEnd, const WTF::String& replace, int start, int end, 2770 int textGeneration) 2771{ 2772 WebCore::Node* focus = currentFocus(); 2773 if (!focus) 2774 return; 2775 setSelection(oldStart, oldEnd); 2776 // Prevent our editor client from passing a message to change the 2777 // selection. 2778 EditorClientAndroid* client = static_cast<EditorClientAndroid*>( 2779 m_mainFrame->editor()->client()); 2780 client->setUiGeneratedSelectionChange(true); 2781 WebCore::TypingCommand::insertText(focus->document(), replace, 2782 false); 2783 client->setUiGeneratedSelectionChange(false); 2784 // setSelection calls revealSelection, so there is no need to do it here. 2785 setSelection(start, end); 2786 m_textGeneration = textGeneration; 2787 m_shouldPaintCaret = true; 2788} 2789 2790void WebViewCore::passToJs(int generation, const WTF::String& current, 2791 const PlatformKeyboardEvent& event) 2792{ 2793 WebCore::Node* focus = currentFocus(); 2794 if (!focus) { 2795 DBG_NAV_LOG("!focus"); 2796 clearTextEntry(); 2797 return; 2798 } 2799 WebCore::RenderObject* renderer = focus->renderer(); 2800 if (!renderer || (!renderer->isTextField() && !renderer->isTextArea())) { 2801 DBG_NAV_LOGD("renderer==%p || not text", renderer); 2802 clearTextEntry(); 2803 return; 2804 } 2805 // Block text field updates during a key press. 2806 m_blockTextfieldUpdates = true; 2807 // Also prevent our editor client from passing a message to change the 2808 // selection. 2809 EditorClientAndroid* client = static_cast<EditorClientAndroid*>( 2810 m_mainFrame->editor()->client()); 2811 client->setUiGeneratedSelectionChange(true); 2812 key(event); 2813 client->setUiGeneratedSelectionChange(false); 2814 m_blockTextfieldUpdates = false; 2815 m_textGeneration = generation; 2816 WebCore::RenderTextControl* renderText = 2817 static_cast<WebCore::RenderTextControl*>(renderer); 2818 WTF::String test = renderText->text(); 2819 if (test != current) { 2820 // If the text changed during the key event, update the UI text field. 2821 updateTextfield(focus, false, test); 2822 } else { 2823 DBG_NAV_LOG("test == current"); 2824 } 2825 // Now that the selection has settled down, send it. 2826 updateTextSelection(); 2827 m_shouldPaintCaret = true; 2828} 2829 2830void WebViewCore::scrollFocusedTextInput(float xPercent, int y) 2831{ 2832 WebCore::Node* focus = currentFocus(); 2833 if (!focus) { 2834 DBG_NAV_LOG("!focus"); 2835 clearTextEntry(); 2836 return; 2837 } 2838 WebCore::RenderObject* renderer = focus->renderer(); 2839 if (!renderer || (!renderer->isTextField() && !renderer->isTextArea())) { 2840 DBG_NAV_LOGD("renderer==%p || not text", renderer); 2841 clearTextEntry(); 2842 return; 2843 } 2844 WebCore::RenderTextControl* renderText = 2845 static_cast<WebCore::RenderTextControl*>(renderer); 2846 int x = (int) (xPercent * (renderText->scrollWidth() - 2847 renderText->clientWidth())); 2848 DBG_NAV_LOGD("x=%d y=%d xPercent=%g scrollW=%d clientW=%d", x, y, 2849 xPercent, renderText->scrollWidth(), renderText->clientWidth()); 2850 renderText->setScrollLeft(x); 2851 renderText->setScrollTop(y); 2852} 2853 2854void WebViewCore::setFocusControllerActive(bool active) 2855{ 2856 m_mainFrame->page()->focusController()->setActive(active); 2857} 2858 2859void WebViewCore::saveDocumentState(WebCore::Frame* frame) 2860{ 2861 if (!CacheBuilder::validNode(m_mainFrame, frame, 0)) 2862 frame = m_mainFrame; 2863 WebCore::HistoryItem *item = frame->loader()->history()->currentItem(); 2864 2865 // item can be null when there is no offical URL for the current page. This happens 2866 // when the content is loaded using with WebCoreFrameBridge::LoadData() and there 2867 // is no failing URL (common case is when content is loaded using data: scheme) 2868 if (item) { 2869 item->setDocumentState(frame->document()->formElementsState()); 2870 } 2871} 2872 2873// Create an array of java Strings. 2874static jobjectArray makeLabelArray(JNIEnv* env, const uint16_t** labels, size_t count) 2875{ 2876 jclass stringClass = env->FindClass("java/lang/String"); 2877 LOG_ASSERT(stringClass, "Could not find java/lang/String"); 2878 jobjectArray array = env->NewObjectArray(count, stringClass, 0); 2879 LOG_ASSERT(array, "Could not create new string array"); 2880 2881 for (size_t i = 0; i < count; i++) { 2882 jobject newString = env->NewString(&labels[i][1], labels[i][0]); 2883 env->SetObjectArrayElement(array, i, newString); 2884 env->DeleteLocalRef(newString); 2885 checkException(env); 2886 } 2887 env->DeleteLocalRef(stringClass); 2888 return array; 2889} 2890 2891void WebViewCore::openFileChooser(PassRefPtr<WebCore::FileChooser> chooser) { 2892 if (!chooser) 2893 return; 2894 JNIEnv* env = JSC::Bindings::getJNIEnv(); 2895 2896 WTF::String acceptType = chooser->acceptTypes(); 2897 jstring jAcceptType = wtfStringToJstring(env, acceptType, true); 2898 jstring jName = (jstring) env->CallObjectMethod( 2899 m_javaGlue->object(env).get(), m_javaGlue->m_openFileChooser, jAcceptType); 2900 checkException(env); 2901 env->DeleteLocalRef(jAcceptType); 2902 2903 const UChar* string = static_cast<const UChar*>(env->GetStringChars(jName, NULL)); 2904 2905 if (!string) 2906 return; 2907 2908 WTF::String webcoreString = jstringToWtfString(env, jName); 2909 env->ReleaseStringChars(jName, string); 2910 2911 if (webcoreString.length()) 2912 chooser->chooseFile(webcoreString); 2913} 2914 2915void WebViewCore::listBoxRequest(WebCoreReply* reply, const uint16_t** labels, size_t count, const int enabled[], size_t enabledCount, 2916 bool multiple, const int selected[], size_t selectedCountOrSelection) 2917{ 2918 // If m_popupReply is not null, then we already have a list showing. 2919 if (m_popupReply != 0) 2920 return; 2921 2922 LOG_ASSERT(m_javaGlue->m_obj, "No java widget associated with this view!"); 2923 2924 // Create an array of java Strings for the drop down. 2925 JNIEnv* env = JSC::Bindings::getJNIEnv(); 2926 jobjectArray labelArray = makeLabelArray(env, labels, count); 2927 2928 // Create an array determining whether each item is enabled. 2929 jintArray enabledArray = env->NewIntArray(enabledCount); 2930 checkException(env); 2931 jint* ptrArray = env->GetIntArrayElements(enabledArray, 0); 2932 checkException(env); 2933 for (size_t i = 0; i < enabledCount; i++) { 2934 ptrArray[i] = enabled[i]; 2935 } 2936 env->ReleaseIntArrayElements(enabledArray, ptrArray, 0); 2937 checkException(env); 2938 2939 if (multiple) { 2940 // Pass up an array representing which items are selected. 2941 jintArray selectedArray = env->NewIntArray(selectedCountOrSelection); 2942 checkException(env); 2943 jint* selArray = env->GetIntArrayElements(selectedArray, 0); 2944 checkException(env); 2945 for (size_t i = 0; i < selectedCountOrSelection; i++) { 2946 selArray[i] = selected[i]; 2947 } 2948 env->ReleaseIntArrayElements(selectedArray, selArray, 0); 2949 2950 env->CallVoidMethod(m_javaGlue->object(env).get(), 2951 m_javaGlue->m_requestListBox, labelArray, enabledArray, 2952 selectedArray); 2953 env->DeleteLocalRef(selectedArray); 2954 } else { 2955 // Pass up the single selection. 2956 env->CallVoidMethod(m_javaGlue->object(env).get(), 2957 m_javaGlue->m_requestSingleListBox, labelArray, enabledArray, 2958 selectedCountOrSelection); 2959 } 2960 2961 env->DeleteLocalRef(labelArray); 2962 env->DeleteLocalRef(enabledArray); 2963 checkException(env); 2964 2965 Retain(reply); 2966 m_popupReply = reply; 2967} 2968 2969bool WebViewCore::key(const PlatformKeyboardEvent& event) 2970{ 2971 WebCore::EventHandler* eventHandler; 2972 WebCore::Node* focusNode = currentFocus(); 2973 DBG_NAV_LOGD("keyCode=%s unichar=%d focusNode=%p", 2974 event.keyIdentifier().utf8().data(), event.unichar(), focusNode); 2975 if (focusNode) { 2976 WebCore::Frame* frame = focusNode->document()->frame(); 2977 WebFrame* webFrame = WebFrame::getWebFrame(frame); 2978 eventHandler = frame->eventHandler(); 2979 VisibleSelection old = frame->selection()->selection(); 2980 bool handled = eventHandler->keyEvent(event); 2981 if (isContentEditable(focusNode)) { 2982 // keyEvent will return true even if the contentEditable did not 2983 // change its selection. In the case that it does not, we want to 2984 // return false so that the key will be sent back to our navigation 2985 // system. 2986 handled |= frame->selection()->selection() != old; 2987 } 2988 return handled; 2989 } else { 2990 eventHandler = m_mainFrame->eventHandler(); 2991 } 2992 return eventHandler->keyEvent(event); 2993} 2994 2995// For when the user clicks the trackball, presses dpad center, or types into an 2996// unfocused textfield. In the latter case, 'fake' will be true 2997void WebViewCore::click(WebCore::Frame* frame, WebCore::Node* node, bool fake) { 2998 if (!node) { 2999 WebCore::IntPoint pt = m_mousePos; 3000 pt.move(m_scrollOffsetX, m_scrollOffsetY); 3001 WebCore::HitTestResult hitTestResult = m_mainFrame->eventHandler()-> 3002 hitTestResultAtPoint(pt, false); 3003 node = hitTestResult.innerNode(); 3004 frame = node->document()->frame(); 3005 DBG_NAV_LOGD("m_mousePos=(%d,%d) m_scrollOffset=(%d,%d) pt=(%d,%d)" 3006 " node=%p", m_mousePos.x(), m_mousePos.y(), 3007 m_scrollOffsetX, m_scrollOffsetY, pt.x(), pt.y(), node); 3008 } 3009 if (node) { 3010 EditorClientAndroid* client 3011 = static_cast<EditorClientAndroid*>( 3012 m_mainFrame->editor()->client()); 3013 client->setShouldChangeSelectedRange(false); 3014 handleMouseClick(frame, node, fake); 3015 client->setShouldChangeSelectedRange(true); 3016 } 3017} 3018 3019#if USE(ACCELERATED_COMPOSITING) 3020GraphicsLayerAndroid* WebViewCore::graphicsRootLayer() const 3021{ 3022 RenderView* contentRenderer = m_mainFrame->contentRenderer(); 3023 if (!contentRenderer) 3024 return 0; 3025 return static_cast<GraphicsLayerAndroid*>( 3026 contentRenderer->compositor()->rootPlatformLayer()); 3027} 3028#endif 3029 3030bool WebViewCore::handleTouchEvent(int action, Vector<int>& ids, Vector<IntPoint>& points, int actionIndex, int metaState) 3031{ 3032 bool preventDefault = false; 3033 3034#if USE(ACCELERATED_COMPOSITING) 3035 GraphicsLayerAndroid* rootLayer = graphicsRootLayer(); 3036 if (rootLayer) 3037 rootLayer->pauseDisplay(true); 3038#endif 3039 3040#if ENABLE(TOUCH_EVENTS) // Android 3041 #define MOTION_EVENT_ACTION_POINTER_DOWN 5 3042 #define MOTION_EVENT_ACTION_POINTER_UP 6 3043 3044 WebCore::TouchEventType type = WebCore::TouchStart; 3045 WebCore::PlatformTouchPoint::State defaultTouchState; 3046 Vector<WebCore::PlatformTouchPoint::State> touchStates(points.size()); 3047 3048 switch (action) { 3049 case 0: // MotionEvent.ACTION_DOWN 3050 type = WebCore::TouchStart; 3051 defaultTouchState = WebCore::PlatformTouchPoint::TouchPressed; 3052 break; 3053 case 1: // MotionEvent.ACTION_UP 3054 type = WebCore::TouchEnd; 3055 defaultTouchState = WebCore::PlatformTouchPoint::TouchReleased; 3056 break; 3057 case 2: // MotionEvent.ACTION_MOVE 3058 type = WebCore::TouchMove; 3059 defaultTouchState = WebCore::PlatformTouchPoint::TouchMoved; 3060 break; 3061 case 3: // MotionEvent.ACTION_CANCEL 3062 type = WebCore::TouchCancel; 3063 defaultTouchState = WebCore::PlatformTouchPoint::TouchCancelled; 3064 break; 3065 case 5: // MotionEvent.ACTION_POINTER_DOWN 3066 type = WebCore::TouchStart; 3067 defaultTouchState = WebCore::PlatformTouchPoint::TouchStationary; 3068 break; 3069 case 6: // MotionEvent.ACTION_POINTER_UP 3070 type = WebCore::TouchEnd; 3071 defaultTouchState = WebCore::PlatformTouchPoint::TouchStationary; 3072 break; 3073 case 0x100: // WebViewCore.ACTION_LONGPRESS 3074 type = WebCore::TouchLongPress; 3075 defaultTouchState = WebCore::PlatformTouchPoint::TouchPressed; 3076 break; 3077 case 0x200: // WebViewCore.ACTION_DOUBLETAP 3078 type = WebCore::TouchDoubleTap; 3079 defaultTouchState = WebCore::PlatformTouchPoint::TouchPressed; 3080 break; 3081 default: 3082 // We do not support other kinds of touch event inside WebCore 3083 // at the moment. 3084 LOGW("Java passed a touch event type that we do not support in WebCore: %d", action); 3085 return 0; 3086 } 3087 3088 for (int c = 0; c < static_cast<int>(points.size()); c++) { 3089 points[c].setX(points[c].x() - m_scrollOffsetX); 3090 points[c].setY(points[c].y() - m_scrollOffsetY); 3091 3092 // Setting the touch state for each point. 3093 // Note: actionIndex will be 0 for all actions that are not ACTION_POINTER_DOWN/UP. 3094 if (action == MOTION_EVENT_ACTION_POINTER_DOWN && c == actionIndex) { 3095 touchStates[c] = WebCore::PlatformTouchPoint::TouchPressed; 3096 } else if (action == MOTION_EVENT_ACTION_POINTER_UP && c == actionIndex) { 3097 touchStates[c] = WebCore::PlatformTouchPoint::TouchReleased; 3098 } else { 3099 touchStates[c] = defaultTouchState; 3100 }; 3101 } 3102 3103 WebCore::PlatformTouchEvent te(ids, points, type, touchStates, metaState); 3104 preventDefault = m_mainFrame->eventHandler()->handleTouchEvent(te); 3105#endif 3106 3107#if USE(ACCELERATED_COMPOSITING) 3108 if (rootLayer) 3109 rootLayer->pauseDisplay(false); 3110#endif 3111 return preventDefault; 3112} 3113 3114void WebViewCore::touchUp(int touchGeneration, 3115 WebCore::Frame* frame, WebCore::Node* node, int x, int y) 3116{ 3117 if (touchGeneration == 0) { 3118 // m_mousePos should be set in getTouchHighlightRects() 3119 WebCore::HitTestResult hitTestResult = m_mainFrame->eventHandler()->hitTestResultAtPoint(m_mousePos, false); 3120 node = hitTestResult.innerNode(); 3121 if (node) 3122 frame = node->document()->frame(); 3123 else 3124 frame = 0; 3125 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); 3126 } else { 3127 if (m_touchGeneration > touchGeneration) { 3128 DBG_NAV_LOGD("m_touchGeneration=%d > touchGeneration=%d" 3129 " x=%d y=%d", m_touchGeneration, touchGeneration, x, y); 3130 return; // short circuit if a newer touch has been generated 3131 } 3132 // This moves m_mousePos to the correct place, and handleMouseClick uses 3133 // m_mousePos to determine where the click happens. 3134 moveMouse(frame, x, y); 3135 m_lastGeneration = touchGeneration; 3136 } 3137 if (frame && CacheBuilder::validNode(m_mainFrame, frame, 0)) { 3138 frame->loader()->resetMultipleFormSubmissionProtection(); 3139 } 3140 DBG_NAV_LOGD("touchGeneration=%d handleMouseClick frame=%p node=%p" 3141 " x=%d y=%d", touchGeneration, frame, node, x, y); 3142 handleMouseClick(frame, node, false); 3143} 3144 3145// Check for the "x-webkit-soft-keyboard" attribute. If it is there and 3146// set to hidden, do not show the soft keyboard. Node passed as a parameter 3147// must not be null. 3148static bool shouldSuppressKeyboard(const WebCore::Node* node) { 3149 LOG_ASSERT(node, "node passed to shouldSuppressKeyboard cannot be null"); 3150 const NamedNodeMap* attributes = node->attributes(); 3151 if (!attributes) return false; 3152 size_t length = attributes->length(); 3153 for (size_t i = 0; i < length; i++) { 3154 const Attribute* a = attributes->attributeItem(i); 3155 if (a->localName() == "x-webkit-soft-keyboard" && a->value() == "hidden") 3156 return true; 3157 } 3158 return false; 3159} 3160 3161// Common code for both clicking with the trackball and touchUp 3162// Also used when typing into a non-focused textfield to give the textfield focus, 3163// in which case, 'fake' is set to true 3164bool WebViewCore::handleMouseClick(WebCore::Frame* framePtr, WebCore::Node* nodePtr, bool fake) 3165{ 3166 bool valid = !framePtr || CacheBuilder::validNode(m_mainFrame, framePtr, nodePtr); 3167 WebFrame* webFrame = WebFrame::getWebFrame(m_mainFrame); 3168 if (valid && nodePtr) { 3169 // Need to special case area tags because an image map could have an area element in the middle 3170 // so when attempting to get the default, the point chosen would be follow the wrong link. 3171 if (nodePtr->hasTagName(WebCore::HTMLNames::areaTag)) { 3172 webFrame->setUserInitiatedAction(true); 3173 nodePtr->dispatchSimulatedClick(0, true, true); 3174 webFrame->setUserInitiatedAction(false); 3175 DBG_NAV_LOG("area"); 3176 return true; 3177 } 3178 } 3179 if (!valid || !framePtr) 3180 framePtr = m_mainFrame; 3181 webFrame->setUserInitiatedAction(true); 3182 WebCore::PlatformMouseEvent mouseDown(m_mousePos, m_mousePos, WebCore::LeftButton, 3183 WebCore::MouseEventPressed, 1, false, false, false, false, 3184 WTF::currentTime()); 3185 // ignore the return from as it will return true if the hit point can trigger selection change 3186 framePtr->eventHandler()->handleMousePressEvent(mouseDown); 3187 WebCore::PlatformMouseEvent mouseUp(m_mousePos, m_mousePos, WebCore::LeftButton, 3188 WebCore::MouseEventReleased, 1, false, false, false, false, 3189 WTF::currentTime()); 3190 bool handled = framePtr->eventHandler()->handleMouseReleaseEvent(mouseUp); 3191 webFrame->setUserInitiatedAction(false); 3192 3193 // If the user clicked on a textfield, make the focusController active 3194 // so we show the blinking cursor. 3195 WebCore::Node* focusNode = currentFocus(); 3196 DBG_NAV_LOGD("m_mousePos={%d,%d} focusNode=%p handled=%s", m_mousePos.x(), 3197 m_mousePos.y(), focusNode, handled ? "true" : "false"); 3198 if (focusNode) { 3199 WebCore::RenderObject* renderer = focusNode->renderer(); 3200 if (renderer && (renderer->isTextField() || renderer->isTextArea())) { 3201 bool ime = !shouldSuppressKeyboard(focusNode) 3202 && !(static_cast<WebCore::HTMLInputElement*>(focusNode))->readOnly(); 3203 if (ime) { 3204#if ENABLE(WEB_AUTOFILL) 3205 if (renderer->isTextField()) { 3206 EditorClientAndroid* editorC = static_cast<EditorClientAndroid*>(framePtr->page()->editorClient()); 3207 WebAutoFill* autoFill = editorC->getAutoFill(); 3208 autoFill->formFieldFocused(static_cast<HTMLFormControlElement*>(focusNode)); 3209 } 3210#endif 3211 if (!fake) { 3212 RenderTextControl* rtc 3213 = static_cast<RenderTextControl*> (renderer); 3214 requestKeyboardWithSelection(focusNode, rtc->selectionStart(), 3215 rtc->selectionEnd()); 3216 } 3217 } else if (!fake) { 3218 requestKeyboard(false); 3219 } 3220 } else if (!fake){ 3221 // If the selection is contentEditable, show the keyboard so the 3222 // user can type. Otherwise hide the keyboard because no text 3223 // input is needed. 3224 if (isContentEditable(focusNode)) { 3225 requestKeyboard(true); 3226 } else if (!nodeIsPlugin(focusNode)) { 3227 clearTextEntry(); 3228 } 3229 } 3230 } else if (!fake) { 3231 // There is no focusNode, so the keyboard is not needed. 3232 clearTextEntry(); 3233 } 3234 return handled; 3235} 3236 3237void WebViewCore::popupReply(int index) 3238{ 3239 if (m_popupReply) { 3240 m_popupReply->replyInt(index); 3241 Release(m_popupReply); 3242 m_popupReply = 0; 3243 } 3244} 3245 3246void WebViewCore::popupReply(const int* array, int count) 3247{ 3248 if (m_popupReply) { 3249 m_popupReply->replyIntArray(array, count); 3250 Release(m_popupReply); 3251 m_popupReply = 0; 3252 } 3253} 3254 3255void WebViewCore::formDidBlur(const WebCore::Node* node) 3256{ 3257 // If the blur is on a text input, keep track of the node so we can 3258 // hide the soft keyboard when the new focus is set, if it is not a 3259 // text input. 3260 if (isTextInput(node)) 3261 m_blurringNodePointer = reinterpret_cast<int>(node); 3262} 3263 3264void WebViewCore::focusNodeChanged(const WebCore::Node* newFocus) 3265{ 3266 if (isTextInput(newFocus)) 3267 m_shouldPaintCaret = true; 3268 else if (m_blurringNodePointer) { 3269 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3270 env->CallVoidMethod(m_javaGlue->object(env).get(), 3271 m_javaGlue->m_formDidBlur, m_blurringNodePointer); 3272 checkException(env); 3273 m_blurringNodePointer = 0; 3274 } 3275} 3276 3277void WebViewCore::addMessageToConsole(const WTF::String& message, unsigned int lineNumber, const WTF::String& sourceID, int msgLevel) { 3278 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3279 jstring jMessageStr = wtfStringToJstring(env, message); 3280 jstring jSourceIDStr = wtfStringToJstring(env, sourceID); 3281 env->CallVoidMethod(m_javaGlue->object(env).get(), 3282 m_javaGlue->m_addMessageToConsole, jMessageStr, lineNumber, 3283 jSourceIDStr, msgLevel); 3284 env->DeleteLocalRef(jMessageStr); 3285 env->DeleteLocalRef(jSourceIDStr); 3286 checkException(env); 3287} 3288 3289void WebViewCore::jsAlert(const WTF::String& url, const WTF::String& text) 3290{ 3291 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3292 jstring jInputStr = wtfStringToJstring(env, text); 3293 jstring jUrlStr = wtfStringToJstring(env, url); 3294 env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_jsAlert, jUrlStr, jInputStr); 3295 env->DeleteLocalRef(jInputStr); 3296 env->DeleteLocalRef(jUrlStr); 3297 checkException(env); 3298} 3299 3300void WebViewCore::exceededDatabaseQuota(const WTF::String& url, const WTF::String& databaseIdentifier, const unsigned long long currentQuota, unsigned long long estimatedSize) 3301{ 3302#if ENABLE(DATABASE) 3303 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3304 jstring jDatabaseIdentifierStr = wtfStringToJstring(env, databaseIdentifier); 3305 jstring jUrlStr = wtfStringToJstring(env, url); 3306 env->CallVoidMethod(m_javaGlue->object(env).get(), 3307 m_javaGlue->m_exceededDatabaseQuota, jUrlStr, 3308 jDatabaseIdentifierStr, currentQuota, estimatedSize); 3309 env->DeleteLocalRef(jDatabaseIdentifierStr); 3310 env->DeleteLocalRef(jUrlStr); 3311 checkException(env); 3312#endif 3313} 3314 3315void WebViewCore::reachedMaxAppCacheSize(const unsigned long long spaceNeeded) 3316{ 3317#if ENABLE(OFFLINE_WEB_APPLICATIONS) 3318 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3319 env->CallVoidMethod(m_javaGlue->object(env).get(), 3320 m_javaGlue->m_reachedMaxAppCacheSize, spaceNeeded); 3321 checkException(env); 3322#endif 3323} 3324 3325void WebViewCore::populateVisitedLinks(WebCore::PageGroup* group) 3326{ 3327 m_groupForVisitedLinks = group; 3328 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3329 env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_populateVisitedLinks); 3330 checkException(env); 3331} 3332 3333void WebViewCore::geolocationPermissionsShowPrompt(const WTF::String& origin) 3334{ 3335 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3336 jstring originString = wtfStringToJstring(env, origin); 3337 env->CallVoidMethod(m_javaGlue->object(env).get(), 3338 m_javaGlue->m_geolocationPermissionsShowPrompt, 3339 originString); 3340 env->DeleteLocalRef(originString); 3341 checkException(env); 3342} 3343 3344void WebViewCore::geolocationPermissionsHidePrompt() 3345{ 3346 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3347 env->CallVoidMethod(m_javaGlue->object(env).get(), 3348 m_javaGlue->m_geolocationPermissionsHidePrompt); 3349 checkException(env); 3350} 3351 3352jobject WebViewCore::getDeviceMotionService() 3353{ 3354 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3355 jobject object = env->CallObjectMethod(m_javaGlue->object(env).get(), 3356 m_javaGlue->m_getDeviceMotionService); 3357 checkException(env); 3358 return object; 3359} 3360 3361jobject WebViewCore::getDeviceOrientationService() 3362{ 3363 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3364 jobject object = env->CallObjectMethod(m_javaGlue->object(env).get(), 3365 m_javaGlue->m_getDeviceOrientationService); 3366 checkException(env); 3367 return object; 3368} 3369 3370bool WebViewCore::jsConfirm(const WTF::String& url, const WTF::String& text) 3371{ 3372 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3373 jstring jInputStr = wtfStringToJstring(env, text); 3374 jstring jUrlStr = wtfStringToJstring(env, url); 3375 jboolean result = env->CallBooleanMethod(m_javaGlue->object(env).get(), m_javaGlue->m_jsConfirm, jUrlStr, jInputStr); 3376 env->DeleteLocalRef(jInputStr); 3377 env->DeleteLocalRef(jUrlStr); 3378 checkException(env); 3379 return result; 3380} 3381 3382bool WebViewCore::jsPrompt(const WTF::String& url, const WTF::String& text, const WTF::String& defaultValue, WTF::String& result) 3383{ 3384 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3385 jstring jUrlStr = wtfStringToJstring(env, url); 3386 jstring jInputStr = wtfStringToJstring(env, text); 3387 jstring jDefaultStr = wtfStringToJstring(env, defaultValue); 3388 jstring returnVal = static_cast<jstring>(env->CallObjectMethod(m_javaGlue->object(env).get(), m_javaGlue->m_jsPrompt, jUrlStr, jInputStr, jDefaultStr)); 3389 env->DeleteLocalRef(jUrlStr); 3390 env->DeleteLocalRef(jInputStr); 3391 env->DeleteLocalRef(jDefaultStr); 3392 checkException(env); 3393 3394 // If returnVal is null, it means that the user cancelled the dialog. 3395 if (!returnVal) 3396 return false; 3397 3398 result = jstringToWtfString(env, returnVal); 3399 env->DeleteLocalRef(returnVal); 3400 return true; 3401} 3402 3403bool WebViewCore::jsUnload(const WTF::String& url, const WTF::String& message) 3404{ 3405 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3406 jstring jInputStr = wtfStringToJstring(env, message); 3407 jstring jUrlStr = wtfStringToJstring(env, url); 3408 jboolean result = env->CallBooleanMethod(m_javaGlue->object(env).get(), m_javaGlue->m_jsUnload, jUrlStr, jInputStr); 3409 env->DeleteLocalRef(jInputStr); 3410 env->DeleteLocalRef(jUrlStr); 3411 checkException(env); 3412 return result; 3413} 3414 3415bool WebViewCore::jsInterrupt() 3416{ 3417 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3418 jboolean result = env->CallBooleanMethod(m_javaGlue->object(env).get(), m_javaGlue->m_jsInterrupt); 3419 checkException(env); 3420 return result; 3421} 3422 3423AutoJObject 3424WebViewCore::getJavaObject() 3425{ 3426 return m_javaGlue->object(JSC::Bindings::getJNIEnv()); 3427} 3428 3429jobject 3430WebViewCore::getWebViewJavaObject() 3431{ 3432 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3433 return env->GetObjectField(m_javaGlue->object(env).get(), gWebViewCoreFields.m_webView); 3434} 3435 3436void WebViewCore::updateTextSelection() { 3437 WebCore::Node* focusNode = currentFocus(); 3438 if (!focusNode) 3439 return; 3440 RenderObject* renderer = focusNode->renderer(); 3441 if (!renderer || (!renderer->isTextArea() && !renderer->isTextField())) 3442 return; 3443 RenderTextControl* rtc = static_cast<RenderTextControl*>(renderer); 3444 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3445 env->CallVoidMethod(m_javaGlue->object(env).get(), 3446 m_javaGlue->m_updateTextSelection, reinterpret_cast<int>(focusNode), 3447 rtc->selectionStart(), rtc->selectionEnd(), m_textGeneration); 3448 checkException(env); 3449} 3450 3451void WebViewCore::updateTextfield(WebCore::Node* ptr, bool changeToPassword, 3452 const WTF::String& text) 3453{ 3454 if (m_blockTextfieldUpdates) 3455 return; 3456 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3457 if (changeToPassword) { 3458 env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_updateTextfield, 3459 (int) ptr, true, 0, m_textGeneration); 3460 checkException(env); 3461 return; 3462 } 3463 jstring string = wtfStringToJstring(env, text); 3464 env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_updateTextfield, 3465 (int) ptr, false, string, m_textGeneration); 3466 env->DeleteLocalRef(string); 3467 checkException(env); 3468} 3469 3470void WebViewCore::clearTextEntry() 3471{ 3472 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3473 env->CallVoidMethod(m_javaGlue->object(env).get(), 3474 m_javaGlue->m_clearTextEntry); 3475} 3476 3477void WebViewCore::setBackgroundColor(SkColor c) 3478{ 3479 WebCore::FrameView* view = m_mainFrame->view(); 3480 if (!view) 3481 return; 3482 3483 // need (int) cast to find the right constructor 3484 WebCore::Color bcolor((int)SkColorGetR(c), (int)SkColorGetG(c), 3485 (int)SkColorGetB(c), (int)SkColorGetA(c)); 3486 view->setBaseBackgroundColor(bcolor); 3487 3488 // Background color of 0 indicates we want a transparent background 3489 if (c == 0) 3490 view->setTransparent(true); 3491} 3492 3493jclass WebViewCore::getPluginClass(const WTF::String& libName, const char* className) 3494{ 3495 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3496 3497 jstring libString = wtfStringToJstring(env, libName); 3498 jstring classString = env->NewStringUTF(className); 3499 jobject pluginClass = env->CallObjectMethod(m_javaGlue->object(env).get(), 3500 m_javaGlue->m_getPluginClass, 3501 libString, classString); 3502 checkException(env); 3503 3504 // cleanup unneeded local JNI references 3505 env->DeleteLocalRef(libString); 3506 env->DeleteLocalRef(classString); 3507 3508 if (pluginClass != NULL) { 3509 return static_cast<jclass>(pluginClass); 3510 } else { 3511 return NULL; 3512 } 3513} 3514 3515void WebViewCore::showFullScreenPlugin(jobject childView, NPP npp) 3516{ 3517 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3518 AutoJObject obj = m_javaGlue->object(env); 3519 3520 env->CallVoidMethod(obj.get(), 3521 m_javaGlue->m_showFullScreenPlugin, childView, (int)npp); 3522 checkException(env); 3523} 3524 3525void WebViewCore::hideFullScreenPlugin() 3526{ 3527 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3528 env->CallVoidMethod(m_javaGlue->object(env).get(), 3529 m_javaGlue->m_hideFullScreenPlugin); 3530 checkException(env); 3531} 3532 3533jobject WebViewCore::createSurface(jobject view) 3534{ 3535 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3536 jobject result = env->CallObjectMethod(m_javaGlue->object(env).get(), 3537 m_javaGlue->m_createSurface, view); 3538 checkException(env); 3539 return result; 3540} 3541 3542jobject WebViewCore::addSurface(jobject view, int x, int y, int width, int height) 3543{ 3544 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3545 jobject result = env->CallObjectMethod(m_javaGlue->object(env).get(), 3546 m_javaGlue->m_addSurface, 3547 view, x, y, width, height); 3548 checkException(env); 3549 return result; 3550} 3551 3552void WebViewCore::updateSurface(jobject childView, int x, int y, int width, int height) 3553{ 3554 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3555 env->CallVoidMethod(m_javaGlue->object(env).get(), 3556 m_javaGlue->m_updateSurface, childView, 3557 x, y, width, height); 3558 checkException(env); 3559} 3560 3561void WebViewCore::destroySurface(jobject childView) 3562{ 3563 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3564 env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_destroySurface, childView); 3565 checkException(env); 3566} 3567 3568jobject WebViewCore::getContext() 3569{ 3570 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3571 AutoJObject obj = m_javaGlue->object(env); 3572 3573 jobject result = env->CallObjectMethod(obj.get(), m_javaGlue->m_getContext); 3574 checkException(env); 3575 return result; 3576} 3577 3578void WebViewCore::keepScreenOn(bool screenOn) { 3579 if ((screenOn && m_screenOnCounter == 0) || (!screenOn && m_screenOnCounter == 1)) { 3580 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3581 env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_keepScreenOn, screenOn); 3582 checkException(env); 3583 } 3584 3585 // update the counter 3586 if (screenOn) 3587 m_screenOnCounter++; 3588 else if (m_screenOnCounter > 0) 3589 m_screenOnCounter--; 3590} 3591 3592bool WebViewCore::validNodeAndBounds(Frame* frame, Node* node, 3593 const IntRect& originalAbsoluteBounds) 3594{ 3595 bool valid = CacheBuilder::validNode(m_mainFrame, frame, node); 3596 if (!valid) 3597 return false; 3598 RenderObject* renderer = node->renderer(); 3599 if (!renderer) 3600 return false; 3601 IntRect absBounds = node->hasTagName(HTMLNames::areaTag) 3602 ? CacheBuilder::getAreaRect(static_cast<HTMLAreaElement*>(node)) 3603 : renderer->absoluteBoundingBoxRect(); 3604 return absBounds == originalAbsoluteBounds; 3605} 3606 3607void WebViewCore::showRect(int left, int top, int width, int height, 3608 int contentWidth, int contentHeight, float xPercentInDoc, 3609 float xPercentInView, float yPercentInDoc, float yPercentInView) 3610{ 3611 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3612 env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_showRect, 3613 left, top, width, height, contentWidth, contentHeight, 3614 xPercentInDoc, xPercentInView, yPercentInDoc, yPercentInView); 3615 checkException(env); 3616} 3617 3618void WebViewCore::centerFitRect(int x, int y, int width, int height) 3619{ 3620 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3621 env->CallVoidMethod(m_javaGlue->object(env).get(), 3622 m_javaGlue->m_centerFitRect, x, y, width, height); 3623 checkException(env); 3624} 3625 3626 3627void WebViewCore::setScrollbarModes(ScrollbarMode horizontalMode, ScrollbarMode verticalMode) 3628{ 3629 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3630 env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_setScrollbarModes, 3631 horizontalMode, verticalMode); 3632 checkException(env); 3633} 3634 3635void WebViewCore::notifyWebAppCanBeInstalled() 3636{ 3637 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3638 env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_setInstallableWebApp); 3639 checkException(env); 3640} 3641 3642#if ENABLE(VIDEO) 3643void WebViewCore::enterFullscreenForVideoLayer(int layerId, const WTF::String& url) 3644{ 3645 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3646 jstring jUrlStr = wtfStringToJstring(env, url); 3647 env->CallVoidMethod(m_javaGlue->object(env).get(), 3648 m_javaGlue->m_enterFullscreenForVideoLayer, layerId, jUrlStr); 3649 checkException(env); 3650} 3651#endif 3652 3653void WebViewCore::setWebTextViewAutoFillable(int queryId, const string16& previewSummary) 3654{ 3655#if ENABLE(WEB_AUTOFILL) 3656 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3657 jstring preview = env->NewString(previewSummary.data(), previewSummary.length()); 3658 env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_setWebTextViewAutoFillable, queryId, preview); 3659 env->DeleteLocalRef(preview); 3660#endif 3661} 3662 3663bool WebViewCore::drawIsPaused() const 3664{ 3665 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3666 return env->GetBooleanField(m_javaGlue->object(env).get(), 3667 gWebViewCoreFields.m_drawIsPaused); 3668} 3669 3670#if USE(CHROME_NETWORK_STACK) 3671void WebViewCore::setWebRequestContextUserAgent() 3672{ 3673 // We cannot create a WebRequestContext, because we might not know it this is a private tab or not yet 3674 if (m_webRequestContext) 3675 m_webRequestContext->setUserAgent(WebFrame::getWebFrame(m_mainFrame)->userAgentForURL(0)); // URL not used 3676} 3677 3678void WebViewCore::setWebRequestContextCacheMode(int cacheMode) 3679{ 3680 m_cacheMode = cacheMode; 3681 // We cannot create a WebRequestContext, because we might not know it this is a private tab or not yet 3682 if (!m_webRequestContext) 3683 return; 3684 3685 m_webRequestContext->setCacheMode(cacheMode); 3686} 3687 3688WebRequestContext* WebViewCore::webRequestContext() 3689{ 3690 if (!m_webRequestContext) { 3691 Settings* settings = mainFrame()->settings(); 3692 m_webRequestContext = new WebRequestContext(settings && settings->privateBrowsingEnabled()); 3693 setWebRequestContextUserAgent(); 3694 setWebRequestContextCacheMode(m_cacheMode); 3695 } 3696 return m_webRequestContext.get(); 3697} 3698#endif 3699 3700void WebViewCore::scrollRenderLayer(int layer, const SkRect& rect) 3701{ 3702#if USE(ACCELERATED_COMPOSITING) 3703 GraphicsLayerAndroid* root = graphicsRootLayer(); 3704 if (!root) 3705 return; 3706 3707 LayerAndroid* layerAndroid = root->platformLayer(); 3708 if (!layerAndroid) 3709 return; 3710 3711 LayerAndroid* target = layerAndroid->findById(layer); 3712 if (!target) 3713 return; 3714 3715 RenderLayer* owner = target->owningLayer(); 3716 if (!owner) 3717 return; 3718 3719 if (owner->stackingContext()) 3720 owner->scrollToOffset(rect.fLeft, rect.fTop); 3721#endif 3722} 3723 3724//---------------------------------------------------------------------- 3725// Native JNI methods 3726//---------------------------------------------------------------------- 3727static void RevealSelection(JNIEnv *env, jobject obj) 3728{ 3729 GET_NATIVE_VIEW(env, obj)->revealSelection(); 3730} 3731 3732static jstring RequestLabel(JNIEnv *env, jobject obj, int framePointer, 3733 int nodePointer) 3734{ 3735 return wtfStringToJstring(env, GET_NATIVE_VIEW(env, obj)->requestLabel( 3736 (WebCore::Frame*) framePointer, (WebCore::Node*) nodePointer)); 3737} 3738 3739static void ClearContent(JNIEnv *env, jobject obj) 3740{ 3741#ifdef ANDROID_INSTRUMENT 3742 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); 3743#endif 3744 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); 3745 viewImpl->clearContent(); 3746} 3747 3748static void UpdateFrameCacheIfLoading(JNIEnv *env, jobject obj) 3749{ 3750 GET_NATIVE_VIEW(env, obj)->updateFrameCacheIfLoading(); 3751} 3752 3753static void SetSize(JNIEnv *env, jobject obj, jint width, jint height, 3754 jint textWrapWidth, jfloat scale, jint screenWidth, jint screenHeight, 3755 jint anchorX, jint anchorY, jboolean ignoreHeight) 3756{ 3757#ifdef ANDROID_INSTRUMENT 3758 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); 3759#endif 3760 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); 3761 LOGV("webviewcore::nativeSetSize(%u %u)\n viewImpl: %p", (unsigned)width, (unsigned)height, viewImpl); 3762 LOG_ASSERT(viewImpl, "viewImpl not set in nativeSetSize"); 3763 viewImpl->setSizeScreenWidthAndScale(width, height, textWrapWidth, scale, 3764 screenWidth, screenHeight, anchorX, anchorY, ignoreHeight); 3765} 3766 3767static void SetScrollOffset(JNIEnv *env, jobject obj, jint gen, jboolean sendScrollEvent, jint x, jint y) 3768{ 3769#ifdef ANDROID_INSTRUMENT 3770 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); 3771#endif 3772 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); 3773 LOG_ASSERT(viewImpl, "need viewImpl"); 3774 3775 viewImpl->setScrollOffset(gen, sendScrollEvent, x, y); 3776} 3777 3778static void SetGlobalBounds(JNIEnv *env, jobject obj, jint x, jint y, jint h, 3779 jint v) 3780{ 3781#ifdef ANDROID_INSTRUMENT 3782 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); 3783#endif 3784 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); 3785 LOG_ASSERT(viewImpl, "need viewImpl"); 3786 3787 viewImpl->setGlobalBounds(x, y, h, v); 3788} 3789 3790static jboolean Key(JNIEnv *env, jobject obj, jint keyCode, jint unichar, 3791 jint repeatCount, jboolean isShift, jboolean isAlt, jboolean isSym, 3792 jboolean isDown) 3793{ 3794#ifdef ANDROID_INSTRUMENT 3795 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); 3796#endif 3797 return GET_NATIVE_VIEW(env, obj)->key(PlatformKeyboardEvent(keyCode, 3798 unichar, repeatCount, isDown, isShift, isAlt, isSym)); 3799} 3800 3801static void Click(JNIEnv *env, jobject obj, int framePtr, int nodePtr, jboolean fake) 3802{ 3803#ifdef ANDROID_INSTRUMENT 3804 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); 3805#endif 3806 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); 3807 LOG_ASSERT(viewImpl, "viewImpl not set in Click"); 3808 3809 viewImpl->click(reinterpret_cast<WebCore::Frame*>(framePtr), 3810 reinterpret_cast<WebCore::Node*>(nodePtr), fake); 3811} 3812 3813static void ContentInvalidateAll(JNIEnv *env, jobject obj) 3814{ 3815 GET_NATIVE_VIEW(env, obj)->contentInvalidateAll(); 3816} 3817 3818static void DeleteSelection(JNIEnv *env, jobject obj, jint start, jint end, 3819 jint textGeneration) 3820{ 3821#ifdef ANDROID_INSTRUMENT 3822 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); 3823#endif 3824 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); 3825 viewImpl->deleteSelection(start, end, textGeneration); 3826} 3827 3828static void SetSelection(JNIEnv *env, jobject obj, jint start, jint end) 3829{ 3830#ifdef ANDROID_INSTRUMENT 3831 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); 3832#endif 3833 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); 3834 viewImpl->setSelection(start, end); 3835} 3836 3837static jstring ModifySelection(JNIEnv *env, jobject obj, jint direction, jint granularity) 3838{ 3839#ifdef ANDROID_INSTRUMENT 3840 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); 3841#endif 3842 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); 3843 String selectionString = viewImpl->modifySelection(direction, granularity); 3844 return wtfStringToJstring(env, selectionString); 3845} 3846 3847static void ReplaceTextfieldText(JNIEnv *env, jobject obj, 3848 jint oldStart, jint oldEnd, jstring replace, jint start, jint end, 3849 jint textGeneration) 3850{ 3851#ifdef ANDROID_INSTRUMENT 3852 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); 3853#endif 3854 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); 3855 WTF::String webcoreString = jstringToWtfString(env, replace); 3856 viewImpl->replaceTextfieldText(oldStart, 3857 oldEnd, webcoreString, start, end, textGeneration); 3858} 3859 3860static void PassToJs(JNIEnv *env, jobject obj, 3861 jint generation, jstring currentText, jint keyCode, 3862 jint keyValue, jboolean down, jboolean cap, jboolean fn, jboolean sym) 3863{ 3864#ifdef ANDROID_INSTRUMENT 3865 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); 3866#endif 3867 WTF::String current = jstringToWtfString(env, currentText); 3868 GET_NATIVE_VIEW(env, obj)->passToJs(generation, current, 3869 PlatformKeyboardEvent(keyCode, keyValue, 0, down, cap, fn, sym)); 3870} 3871 3872static void ScrollFocusedTextInput(JNIEnv *env, jobject obj, jfloat xPercent, 3873 jint y) 3874{ 3875#ifdef ANDROID_INSTRUMENT 3876 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); 3877#endif 3878 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); 3879 viewImpl->scrollFocusedTextInput(xPercent, y); 3880} 3881 3882static void SetFocusControllerActive(JNIEnv *env, jobject obj, jboolean active) 3883{ 3884#ifdef ANDROID_INSTRUMENT 3885 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); 3886#endif 3887 LOGV("webviewcore::nativeSetFocusControllerActive()\n"); 3888 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); 3889 LOG_ASSERT(viewImpl, "viewImpl not set in nativeSetFocusControllerActive"); 3890 viewImpl->setFocusControllerActive(active); 3891} 3892 3893static void SaveDocumentState(JNIEnv *env, jobject obj, jint frame) 3894{ 3895#ifdef ANDROID_INSTRUMENT 3896 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); 3897#endif 3898 LOGV("webviewcore::nativeSaveDocumentState()\n"); 3899 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); 3900 LOG_ASSERT(viewImpl, "viewImpl not set in nativeSaveDocumentState"); 3901 viewImpl->saveDocumentState((WebCore::Frame*) frame); 3902} 3903 3904void WebViewCore::addVisitedLink(const UChar* string, int length) 3905{ 3906 if (m_groupForVisitedLinks) 3907 m_groupForVisitedLinks->addVisitedLink(string, length); 3908} 3909 3910static jint UpdateLayers(JNIEnv *env, jobject obj, jobject region) 3911{ 3912 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); 3913 BaseLayerAndroid* result = viewImpl->createBaseLayer(); 3914 SkRegion* nativeRegion = GraphicsJNI::getNativeRegion(env, region); 3915 if (result) { 3916 SkIRect bounds; 3917 LayerAndroid* root = static_cast<LayerAndroid*>(result->getChild(0)); 3918 if (root) { 3919 root->bounds().roundOut(&bounds); 3920 nativeRegion->setRect(bounds); 3921 } 3922 } 3923 return reinterpret_cast<jint>(result); 3924} 3925 3926static jint RecordContent(JNIEnv *env, jobject obj, jobject region, jobject pt) 3927{ 3928#ifdef ANDROID_INSTRUMENT 3929 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); 3930#endif 3931 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); 3932 SkRegion* nativeRegion = GraphicsJNI::getNativeRegion(env, region); 3933 SkIPoint nativePt; 3934 BaseLayerAndroid* result = viewImpl->recordContent(nativeRegion, &nativePt); 3935 GraphicsJNI::ipoint_to_jpoint(nativePt, env, pt); 3936 return reinterpret_cast<jint>(result); 3937} 3938 3939static void SplitContent(JNIEnv *env, jobject obj, jint content) 3940{ 3941#ifdef ANDROID_INSTRUMENT 3942 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); 3943#endif 3944 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); 3945 viewImpl->splitContent(reinterpret_cast<PictureSet*>(content)); 3946} 3947 3948static void SendListBoxChoice(JNIEnv* env, jobject obj, jint choice) 3949{ 3950#ifdef ANDROID_INSTRUMENT 3951 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); 3952#endif 3953 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); 3954 LOG_ASSERT(viewImpl, "viewImpl not set in nativeSendListBoxChoice"); 3955 viewImpl->popupReply(choice); 3956} 3957 3958// Set aside a predetermined amount of space in which to place the listbox 3959// choices, to avoid unnecessary allocations. 3960// The size here is arbitrary. We want the size to be at least as great as the 3961// number of items in the average multiple-select listbox. 3962#define PREPARED_LISTBOX_STORAGE 10 3963 3964static void SendListBoxChoices(JNIEnv* env, jobject obj, jbooleanArray jArray, 3965 jint size) 3966{ 3967#ifdef ANDROID_INSTRUMENT 3968 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); 3969#endif 3970 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); 3971 LOG_ASSERT(viewImpl, "viewImpl not set in nativeSendListBoxChoices"); 3972 jboolean* ptrArray = env->GetBooleanArrayElements(jArray, 0); 3973 SkAutoSTMalloc<PREPARED_LISTBOX_STORAGE, int> storage(size); 3974 int* array = storage.get(); 3975 int count = 0; 3976 for (int i = 0; i < size; i++) { 3977 if (ptrArray[i]) { 3978 array[count++] = i; 3979 } 3980 } 3981 env->ReleaseBooleanArrayElements(jArray, ptrArray, JNI_ABORT); 3982 viewImpl->popupReply(array, count); 3983} 3984 3985static jstring FindAddress(JNIEnv *env, jobject obj, jstring addr, 3986 jboolean caseInsensitive) 3987{ 3988#ifdef ANDROID_INSTRUMENT 3989 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); 3990#endif 3991 if (!addr) 3992 return 0; 3993 int length = env->GetStringLength(addr); 3994 if (!length) 3995 return 0; 3996 const jchar* addrChars = env->GetStringChars(addr, 0); 3997 int start, end; 3998 bool success = CacheBuilder::FindAddress(addrChars, length, 3999 &start, &end, caseInsensitive) == CacheBuilder::FOUND_COMPLETE; 4000 jstring ret = 0; 4001 if (success) 4002 ret = env->NewString(addrChars + start, end - start); 4003 env->ReleaseStringChars(addr, addrChars); 4004 return ret; 4005} 4006 4007static jboolean HandleTouchEvent(JNIEnv *env, jobject obj, jint action, jintArray idArray, 4008 jintArray xArray, jintArray yArray, 4009 jint count, jint actionIndex, jint metaState) 4010{ 4011#ifdef ANDROID_INSTRUMENT 4012 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); 4013#endif 4014 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); 4015 LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); 4016 jint* ptrIdArray = env->GetIntArrayElements(idArray, 0); 4017 jint* ptrXArray = env->GetIntArrayElements(xArray, 0); 4018 jint* ptrYArray = env->GetIntArrayElements(yArray, 0); 4019 Vector<int> ids(count); 4020 Vector<IntPoint> points(count); 4021 for (int c = 0; c < count; c++) { 4022 ids[c] = ptrIdArray[c]; 4023 points[c].setX(ptrXArray[c]); 4024 points[c].setY(ptrYArray[c]); 4025 } 4026 env->ReleaseIntArrayElements(idArray, ptrIdArray, JNI_ABORT); 4027 env->ReleaseIntArrayElements(xArray, ptrXArray, JNI_ABORT); 4028 env->ReleaseIntArrayElements(yArray, ptrYArray, JNI_ABORT); 4029 4030 return viewImpl->handleTouchEvent(action, ids, points, actionIndex, metaState); 4031} 4032 4033static void TouchUp(JNIEnv *env, jobject obj, jint touchGeneration, 4034 jint frame, jint node, jint x, jint y) 4035{ 4036#ifdef ANDROID_INSTRUMENT 4037 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); 4038#endif 4039 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); 4040 LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); 4041 viewImpl->touchUp(touchGeneration, 4042 (WebCore::Frame*) frame, (WebCore::Node*) node, x, y); 4043} 4044 4045static jstring RetrieveHref(JNIEnv *env, jobject obj, jint x, jint y) 4046{ 4047#ifdef ANDROID_INSTRUMENT 4048 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); 4049#endif 4050 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); 4051 LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); 4052 WTF::String result = viewImpl->retrieveHref(x, y); 4053 if (!result.isEmpty()) 4054 return wtfStringToJstring(env, result); 4055 return 0; 4056} 4057 4058static jstring RetrieveAnchorText(JNIEnv *env, jobject obj, jint x, jint y) 4059{ 4060#ifdef ANDROID_INSTRUMENT 4061 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); 4062#endif 4063 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); 4064 LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); 4065 WTF::String result = viewImpl->retrieveAnchorText(x, y); 4066 if (!result.isEmpty()) 4067 return wtfStringToJstring(env, result); 4068 return 0; 4069} 4070 4071static jstring RetrieveImageSource(JNIEnv *env, jobject obj, jint x, jint y) 4072{ 4073 WTF::String result = GET_NATIVE_VIEW(env, obj)->retrieveImageSource(x, y); 4074 return !result.isEmpty() ? wtfStringToJstring(env, result) : 0; 4075} 4076 4077static void StopPaintingCaret(JNIEnv *env, jobject obj) 4078{ 4079 GET_NATIVE_VIEW(env, obj)->setShouldPaintCaret(false); 4080} 4081 4082static void MoveFocus(JNIEnv *env, jobject obj, jint framePtr, jint nodePtr) 4083{ 4084#ifdef ANDROID_INSTRUMENT 4085 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); 4086#endif 4087 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); 4088 LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); 4089 viewImpl->moveFocus((WebCore::Frame*) framePtr, (WebCore::Node*) nodePtr); 4090} 4091 4092static void MoveMouse(JNIEnv *env, jobject obj, jint frame, 4093 jint x, jint y) 4094{ 4095#ifdef ANDROID_INSTRUMENT 4096 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); 4097#endif 4098 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); 4099 LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); 4100 viewImpl->moveMouse((WebCore::Frame*) frame, x, y); 4101} 4102 4103static void MoveMouseIfLatest(JNIEnv *env, jobject obj, jint moveGeneration, 4104 jint frame, jint x, jint y) 4105{ 4106#ifdef ANDROID_INSTRUMENT 4107 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); 4108#endif 4109 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); 4110 LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); 4111 viewImpl->moveMouseIfLatest(moveGeneration, 4112 (WebCore::Frame*) frame, x, y); 4113} 4114 4115static void UpdateFrameCache(JNIEnv *env, jobject obj) 4116{ 4117#ifdef ANDROID_INSTRUMENT 4118 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); 4119#endif 4120 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); 4121 LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); 4122 viewImpl->updateFrameCache(); 4123} 4124 4125static jint GetContentMinPrefWidth(JNIEnv *env, jobject obj) 4126{ 4127#ifdef ANDROID_INSTRUMENT 4128 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); 4129#endif 4130 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); 4131 LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); 4132 4133 WebCore::Frame* frame = viewImpl->mainFrame(); 4134 if (frame) { 4135 WebCore::Document* document = frame->document(); 4136 if (document) { 4137 WebCore::RenderObject* renderer = document->renderer(); 4138 if (renderer && renderer->isRenderView()) { 4139 return renderer->minPreferredLogicalWidth(); 4140 } 4141 } 4142 } 4143 return 0; 4144} 4145 4146static void SetViewportSettingsFromNative(JNIEnv *env, jobject obj) 4147{ 4148#ifdef ANDROID_INSTRUMENT 4149 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); 4150#endif 4151 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); 4152 LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); 4153 4154 WebCore::Settings* s = viewImpl->mainFrame()->page()->settings(); 4155 if (!s) 4156 return; 4157 4158#ifdef ANDROID_META_SUPPORT 4159 env->SetIntField(obj, gWebViewCoreFields.m_viewportWidth, s->viewportWidth()); 4160 env->SetIntField(obj, gWebViewCoreFields.m_viewportHeight, s->viewportHeight()); 4161 env->SetIntField(obj, gWebViewCoreFields.m_viewportInitialScale, s->viewportInitialScale()); 4162 env->SetIntField(obj, gWebViewCoreFields.m_viewportMinimumScale, s->viewportMinimumScale()); 4163 env->SetIntField(obj, gWebViewCoreFields.m_viewportMaximumScale, s->viewportMaximumScale()); 4164 env->SetBooleanField(obj, gWebViewCoreFields.m_viewportUserScalable, s->viewportUserScalable()); 4165 env->SetIntField(obj, gWebViewCoreFields.m_viewportDensityDpi, s->viewportTargetDensityDpi()); 4166#endif 4167} 4168 4169static void SetBackgroundColor(JNIEnv *env, jobject obj, jint color) 4170{ 4171#ifdef ANDROID_INSTRUMENT 4172 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); 4173#endif 4174 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); 4175 LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); 4176 4177 viewImpl->setBackgroundColor((SkColor) color); 4178} 4179 4180static void DumpDomTree(JNIEnv *env, jobject obj, jboolean useFile) 4181{ 4182 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); 4183 LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); 4184 4185 viewImpl->dumpDomTree(useFile); 4186} 4187 4188static void DumpRenderTree(JNIEnv *env, jobject obj, jboolean useFile) 4189{ 4190 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); 4191 LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); 4192 4193 viewImpl->dumpRenderTree(useFile); 4194} 4195 4196static void DumpNavTree(JNIEnv *env, jobject obj) 4197{ 4198 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); 4199 LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); 4200 4201 viewImpl->dumpNavTree(); 4202} 4203 4204static void DumpV8Counters(JNIEnv*, jobject) 4205{ 4206#if USE(V8) 4207#ifdef ANDROID_INSTRUMENT 4208 V8Counters::dumpCounters(); 4209#endif 4210#endif 4211} 4212 4213static void SetJsFlags(JNIEnv *env, jobject obj, jstring flags) 4214{ 4215#if USE(V8) 4216 WTF::String flagsString = jstringToWtfString(env, flags); 4217 WTF::CString utf8String = flagsString.utf8(); 4218 WebCore::ScriptController::setFlags(utf8String.data(), utf8String.length()); 4219#endif 4220} 4221 4222 4223// Called from the Java side to set a new quota for the origin or new appcache 4224// max size in response to a notification that the original quota was exceeded or 4225// that the appcache has reached its maximum size. 4226static void SetNewStorageLimit(JNIEnv* env, jobject obj, jlong quota) { 4227#if ENABLE(DATABASE) || ENABLE(OFFLINE_WEB_APPLICATIONS) 4228 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); 4229 Frame* frame = viewImpl->mainFrame(); 4230 4231 // The main thread is blocked awaiting this response, so now we can wake it 4232 // up. 4233 ChromeClientAndroid* chromeC = static_cast<ChromeClientAndroid*>(frame->page()->chrome()->client()); 4234 chromeC->wakeUpMainThreadWithNewQuota(quota); 4235#endif 4236} 4237 4238// Called from Java to provide a Geolocation permission state for the specified origin. 4239static void GeolocationPermissionsProvide(JNIEnv* env, jobject obj, jstring origin, jboolean allow, jboolean remember) { 4240 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); 4241 Frame* frame = viewImpl->mainFrame(); 4242 4243 ChromeClientAndroid* chromeClient = static_cast<ChromeClientAndroid*>(frame->page()->chrome()->client()); 4244 chromeClient->provideGeolocationPermissions(jstringToWtfString(env, origin), allow, remember); 4245} 4246 4247static void RegisterURLSchemeAsLocal(JNIEnv* env, jobject obj, jstring scheme) { 4248#ifdef ANDROID_INSTRUMENT 4249 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); 4250#endif 4251 WebCore::SchemeRegistry::registerURLSchemeAsLocal(jstringToWtfString(env, scheme)); 4252} 4253 4254static bool FocusBoundsChanged(JNIEnv* env, jobject obj) 4255{ 4256 return GET_NATIVE_VIEW(env, obj)->focusBoundsChanged(); 4257} 4258 4259static void Pause(JNIEnv* env, jobject obj) 4260{ 4261 // This is called for the foreground tab when the browser is put to the 4262 // background (and also for any tab when it is put to the background of the 4263 // browser). The browser can only be killed by the system when it is in the 4264 // background, so saving the Geolocation permission state now ensures that 4265 // is maintained when the browser is killed. 4266 ChromeClient* chromeClient = GET_NATIVE_VIEW(env, obj)->mainFrame()->page()->chrome()->client(); 4267 ChromeClientAndroid* chromeClientAndroid = static_cast<ChromeClientAndroid*>(chromeClient); 4268 chromeClientAndroid->storeGeolocationPermissions(); 4269 4270 Frame* mainFrame = GET_NATIVE_VIEW(env, obj)->mainFrame(); 4271 for (Frame* frame = mainFrame; frame; frame = frame->tree()->traverseNext()) { 4272 Geolocation* geolocation = frame->domWindow()->navigator()->optionalGeolocation(); 4273 if (geolocation) 4274 geolocation->suspend(); 4275 } 4276 4277 GET_NATIVE_VIEW(env, obj)->deviceMotionAndOrientationManager()->maybeSuspendClients(); 4278 4279 ANPEvent event; 4280 SkANP::InitEvent(&event, kLifecycle_ANPEventType); 4281 event.data.lifecycle.action = kPause_ANPLifecycleAction; 4282 GET_NATIVE_VIEW(env, obj)->sendPluginEvent(event); 4283 4284 GET_NATIVE_VIEW(env, obj)->setIsPaused(true); 4285} 4286 4287static void Resume(JNIEnv* env, jobject obj) 4288{ 4289 Frame* mainFrame = GET_NATIVE_VIEW(env, obj)->mainFrame(); 4290 for (Frame* frame = mainFrame; frame; frame = frame->tree()->traverseNext()) { 4291 Geolocation* geolocation = frame->domWindow()->navigator()->optionalGeolocation(); 4292 if (geolocation) 4293 geolocation->resume(); 4294 } 4295 4296 GET_NATIVE_VIEW(env, obj)->deviceMotionAndOrientationManager()->maybeResumeClients(); 4297 4298 ANPEvent event; 4299 SkANP::InitEvent(&event, kLifecycle_ANPEventType); 4300 event.data.lifecycle.action = kResume_ANPLifecycleAction; 4301 GET_NATIVE_VIEW(env, obj)->sendPluginEvent(event); 4302 4303 GET_NATIVE_VIEW(env, obj)->setIsPaused(false); 4304} 4305 4306static void FreeMemory(JNIEnv* env, jobject obj) 4307{ 4308 ANPEvent event; 4309 SkANP::InitEvent(&event, kLifecycle_ANPEventType); 4310 event.data.lifecycle.action = kFreeMemory_ANPLifecycleAction; 4311 GET_NATIVE_VIEW(env, obj)->sendPluginEvent(event); 4312} 4313 4314static void ProvideVisitedHistory(JNIEnv *env, jobject obj, jobject hist) 4315{ 4316 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); 4317 LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); 4318 4319 jobjectArray array = static_cast<jobjectArray>(hist); 4320 4321 jsize len = env->GetArrayLength(array); 4322 for (jsize i = 0; i < len; i++) { 4323 jstring item = static_cast<jstring>(env->GetObjectArrayElement(array, i)); 4324 const UChar* str = static_cast<const UChar*>(env->GetStringChars(item, 0)); 4325 jsize len = env->GetStringLength(item); 4326 viewImpl->addVisitedLink(str, len); 4327 env->ReleaseStringChars(item, str); 4328 env->DeleteLocalRef(item); 4329 } 4330} 4331 4332// Notification from the UI thread that the plugin's full-screen surface has been discarded 4333static void FullScreenPluginHidden(JNIEnv* env, jobject obj, jint npp) 4334{ 4335 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); 4336 PluginWidgetAndroid* plugin = viewImpl->getPluginWidget((NPP)npp); 4337 if (plugin) 4338 plugin->exitFullScreen(false); 4339} 4340 4341static WebCore::IntRect jrect_to_webrect(JNIEnv* env, jobject obj) 4342{ 4343 int L, T, R, B; 4344 GraphicsJNI::get_jrect(env, obj, &L, &T, &R, &B); 4345 return WebCore::IntRect(L, T, R - L, B - T); 4346} 4347 4348static bool ValidNodeAndBounds(JNIEnv *env, jobject obj, int frame, int node, 4349 jobject rect) 4350{ 4351 IntRect nativeRect = jrect_to_webrect(env, rect); 4352 return GET_NATIVE_VIEW(env, obj)->validNodeAndBounds( 4353 reinterpret_cast<Frame*>(frame), 4354 reinterpret_cast<Node*>(node), nativeRect); 4355} 4356 4357static jobject GetTouchHighlightRects(JNIEnv* env, jobject obj, jint x, jint y, jint slop) 4358{ 4359 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); 4360 if (!viewImpl) 4361 return 0; 4362 Vector<IntRect> rects = viewImpl->getTouchHighlightRects(x, y, slop); 4363 if (rects.isEmpty()) 4364 return 0; 4365 4366 jclass arrayClass = env->FindClass("java/util/ArrayList"); 4367 LOG_ASSERT(arrayClass, "Could not find java/util/ArrayList"); 4368 jmethodID init = env->GetMethodID(arrayClass, "<init>", "(I)V"); 4369 LOG_ASSERT(init, "Could not find constructor for ArrayList"); 4370 jobject array = env->NewObject(arrayClass, init, rects.size()); 4371 LOG_ASSERT(array, "Could not create a new ArrayList"); 4372 jmethodID add = env->GetMethodID(arrayClass, "add", "(Ljava/lang/Object;)Z"); 4373 LOG_ASSERT(add, "Could not find add method on ArrayList"); 4374 jclass rectClass = env->FindClass("android/graphics/Rect"); 4375 LOG_ASSERT(rectClass, "Could not find android/graphics/Rect"); 4376 jmethodID rectinit = env->GetMethodID(rectClass, "<init>", "(IIII)V"); 4377 LOG_ASSERT(rectinit, "Could not find init method on Rect"); 4378 4379 for (size_t i = 0; i < rects.size(); i++) { 4380 jobject rect = env->NewObject(rectClass, rectinit, rects[i].x(), 4381 rects[i].y(), rects[i].maxX(), rects[i].maxY()); 4382 if (rect) { 4383 env->CallBooleanMethod(array, add, rect); 4384 env->DeleteLocalRef(rect); 4385 } 4386 } 4387 4388 env->DeleteLocalRef(rectClass); 4389 env->DeleteLocalRef(arrayClass); 4390 return array; 4391} 4392 4393static void AutoFillForm(JNIEnv* env, jobject obj, jint queryId) 4394{ 4395#if ENABLE(WEB_AUTOFILL) 4396 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); 4397 if (!viewImpl) 4398 return; 4399 4400 WebCore::Frame* frame = viewImpl->mainFrame(); 4401 if (frame) { 4402 EditorClientAndroid* editorC = static_cast<EditorClientAndroid*>(frame->page()->editorClient()); 4403 WebAutoFill* autoFill = editorC->getAutoFill(); 4404 autoFill->fillFormFields(queryId); 4405 } 4406#endif 4407} 4408 4409static void ScrollRenderLayer(JNIEnv* env, jobject obj, jint layer, jobject jRect) 4410{ 4411 SkRect rect; 4412 GraphicsJNI::jrect_to_rect(env, jRect, &rect); 4413 GET_NATIVE_VIEW(env, obj)->scrollRenderLayer(layer, rect); 4414} 4415 4416// ---------------------------------------------------------------------------- 4417 4418/* 4419 * JNI registration. 4420 */ 4421static JNINativeMethod gJavaWebViewCoreMethods[] = { 4422 { "nativeClearContent", "()V", 4423 (void*) ClearContent }, 4424 { "nativeFocusBoundsChanged", "()Z", 4425 (void*) FocusBoundsChanged } , 4426 { "nativeKey", "(IIIZZZZ)Z", 4427 (void*) Key }, 4428 { "nativeClick", "(IIZ)V", 4429 (void*) Click }, 4430 { "nativeContentInvalidateAll", "()V", 4431 (void*) ContentInvalidateAll }, 4432 { "nativeSendListBoxChoices", "([ZI)V", 4433 (void*) SendListBoxChoices }, 4434 { "nativeSendListBoxChoice", "(I)V", 4435 (void*) SendListBoxChoice }, 4436 { "nativeSetSize", "(IIIFIIIIZ)V", 4437 (void*) SetSize }, 4438 { "nativeSetScrollOffset", "(IZII)V", 4439 (void*) SetScrollOffset }, 4440 { "nativeSetGlobalBounds", "(IIII)V", 4441 (void*) SetGlobalBounds }, 4442 { "nativeSetSelection", "(II)V", 4443 (void*) SetSelection } , 4444 { "nativeModifySelection", "(II)Ljava/lang/String;", 4445 (void*) ModifySelection }, 4446 { "nativeDeleteSelection", "(III)V", 4447 (void*) DeleteSelection } , 4448 { "nativeReplaceTextfieldText", "(IILjava/lang/String;III)V", 4449 (void*) ReplaceTextfieldText } , 4450 { "nativeMoveFocus", "(II)V", 4451 (void*) MoveFocus }, 4452 { "nativeMoveMouse", "(III)V", 4453 (void*) MoveMouse }, 4454 { "nativeMoveMouseIfLatest", "(IIII)V", 4455 (void*) MoveMouseIfLatest }, 4456 { "passToJs", "(ILjava/lang/String;IIZZZZ)V", 4457 (void*) PassToJs }, 4458 { "nativeScrollFocusedTextInput", "(FI)V", 4459 (void*) ScrollFocusedTextInput }, 4460 { "nativeSetFocusControllerActive", "(Z)V", 4461 (void*) SetFocusControllerActive }, 4462 { "nativeSaveDocumentState", "(I)V", 4463 (void*) SaveDocumentState }, 4464 { "nativeFindAddress", "(Ljava/lang/String;Z)Ljava/lang/String;", 4465 (void*) FindAddress }, 4466 { "nativeHandleTouchEvent", "(I[I[I[IIII)Z", 4467 (void*) HandleTouchEvent }, 4468 { "nativeTouchUp", "(IIIII)V", 4469 (void*) TouchUp }, 4470 { "nativeRetrieveHref", "(II)Ljava/lang/String;", 4471 (void*) RetrieveHref }, 4472 { "nativeRetrieveAnchorText", "(II)Ljava/lang/String;", 4473 (void*) RetrieveAnchorText }, 4474 { "nativeRetrieveImageSource", "(II)Ljava/lang/String;", 4475 (void*) RetrieveImageSource }, 4476 { "nativeStopPaintingCaret", "()V", 4477 (void*) StopPaintingCaret }, 4478 { "nativeUpdateFrameCache", "()V", 4479 (void*) UpdateFrameCache }, 4480 { "nativeGetContentMinPrefWidth", "()I", 4481 (void*) GetContentMinPrefWidth }, 4482 { "nativeUpdateLayers", "(Landroid/graphics/Region;)I", 4483 (void*) UpdateLayers }, 4484 { "nativeRecordContent", "(Landroid/graphics/Region;Landroid/graphics/Point;)I", 4485 (void*) RecordContent }, 4486 { "setViewportSettingsFromNative", "()V", 4487 (void*) SetViewportSettingsFromNative }, 4488 { "nativeSplitContent", "(I)V", 4489 (void*) SplitContent }, 4490 { "nativeSetBackgroundColor", "(I)V", 4491 (void*) SetBackgroundColor }, 4492 { "nativeRegisterURLSchemeAsLocal", "(Ljava/lang/String;)V", 4493 (void*) RegisterURLSchemeAsLocal }, 4494 { "nativeDumpDomTree", "(Z)V", 4495 (void*) DumpDomTree }, 4496 { "nativeDumpRenderTree", "(Z)V", 4497 (void*) DumpRenderTree }, 4498 { "nativeDumpNavTree", "()V", 4499 (void*) DumpNavTree }, 4500 { "nativeDumpV8Counters", "()V", 4501 (void*) DumpV8Counters }, 4502 { "nativeSetNewStorageLimit", "(J)V", 4503 (void*) SetNewStorageLimit }, 4504 { "nativeGeolocationPermissionsProvide", "(Ljava/lang/String;ZZ)V", 4505 (void*) GeolocationPermissionsProvide }, 4506 { "nativePause", "()V", (void*) Pause }, 4507 { "nativeResume", "()V", (void*) Resume }, 4508 { "nativeFreeMemory", "()V", (void*) FreeMemory }, 4509 { "nativeSetJsFlags", "(Ljava/lang/String;)V", (void*) SetJsFlags }, 4510 { "nativeRequestLabel", "(II)Ljava/lang/String;", 4511 (void*) RequestLabel }, 4512 { "nativeRevealSelection", "()V", (void*) RevealSelection }, 4513 { "nativeUpdateFrameCacheIfLoading", "()V", 4514 (void*) UpdateFrameCacheIfLoading }, 4515 { "nativeProvideVisitedHistory", "([Ljava/lang/String;)V", 4516 (void*) ProvideVisitedHistory }, 4517 { "nativeFullScreenPluginHidden", "(I)V", 4518 (void*) FullScreenPluginHidden }, 4519 { "nativeValidNodeAndBounds", "(IILandroid/graphics/Rect;)Z", 4520 (void*) ValidNodeAndBounds }, 4521 { "nativeGetTouchHighlightRects", "(III)Ljava/util/ArrayList;", 4522 (void*) GetTouchHighlightRects }, 4523 { "nativeAutoFillForm", "(I)V", 4524 (void*) AutoFillForm }, 4525 { "nativeScrollLayer", "(ILandroid/graphics/Rect;)V", 4526 (void*) ScrollRenderLayer }, 4527}; 4528 4529int registerWebViewCore(JNIEnv* env) 4530{ 4531 jclass widget = env->FindClass("android/webkit/WebViewCore"); 4532 LOG_ASSERT(widget, 4533 "Unable to find class android/webkit/WebViewCore"); 4534 gWebViewCoreFields.m_nativeClass = env->GetFieldID(widget, "mNativeClass", 4535 "I"); 4536 LOG_ASSERT(gWebViewCoreFields.m_nativeClass, 4537 "Unable to find android/webkit/WebViewCore.mNativeClass"); 4538 gWebViewCoreFields.m_viewportWidth = env->GetFieldID(widget, 4539 "mViewportWidth", "I"); 4540 LOG_ASSERT(gWebViewCoreFields.m_viewportWidth, 4541 "Unable to find android/webkit/WebViewCore.mViewportWidth"); 4542 gWebViewCoreFields.m_viewportHeight = env->GetFieldID(widget, 4543 "mViewportHeight", "I"); 4544 LOG_ASSERT(gWebViewCoreFields.m_viewportHeight, 4545 "Unable to find android/webkit/WebViewCore.mViewportHeight"); 4546 gWebViewCoreFields.m_viewportInitialScale = env->GetFieldID(widget, 4547 "mViewportInitialScale", "I"); 4548 LOG_ASSERT(gWebViewCoreFields.m_viewportInitialScale, 4549 "Unable to find android/webkit/WebViewCore.mViewportInitialScale"); 4550 gWebViewCoreFields.m_viewportMinimumScale = env->GetFieldID(widget, 4551 "mViewportMinimumScale", "I"); 4552 LOG_ASSERT(gWebViewCoreFields.m_viewportMinimumScale, 4553 "Unable to find android/webkit/WebViewCore.mViewportMinimumScale"); 4554 gWebViewCoreFields.m_viewportMaximumScale = env->GetFieldID(widget, 4555 "mViewportMaximumScale", "I"); 4556 LOG_ASSERT(gWebViewCoreFields.m_viewportMaximumScale, 4557 "Unable to find android/webkit/WebViewCore.mViewportMaximumScale"); 4558 gWebViewCoreFields.m_viewportUserScalable = env->GetFieldID(widget, 4559 "mViewportUserScalable", "Z"); 4560 LOG_ASSERT(gWebViewCoreFields.m_viewportUserScalable, 4561 "Unable to find android/webkit/WebViewCore.mViewportUserScalable"); 4562 gWebViewCoreFields.m_viewportDensityDpi = env->GetFieldID(widget, 4563 "mViewportDensityDpi", "I"); 4564 LOG_ASSERT(gWebViewCoreFields.m_viewportDensityDpi, 4565 "Unable to find android/webkit/WebViewCore.mViewportDensityDpi"); 4566 gWebViewCoreFields.m_webView = env->GetFieldID(widget, 4567 "mWebView", "Landroid/webkit/WebView;"); 4568 LOG_ASSERT(gWebViewCoreFields.m_webView, 4569 "Unable to find android/webkit/WebViewCore.mWebView"); 4570 gWebViewCoreFields.m_drawIsPaused = env->GetFieldID(widget, 4571 "mDrawIsPaused", "Z"); 4572 LOG_ASSERT(gWebViewCoreFields.m_drawIsPaused, 4573 "Unable to find android/webkit/WebViewCore.mDrawIsPaused"); 4574 gWebViewCoreFields.m_lowMemoryUsageMb = env->GetFieldID(widget, "mLowMemoryUsageThresholdMb", "I"); 4575 gWebViewCoreFields.m_highMemoryUsageMb = env->GetFieldID(widget, "mHighMemoryUsageThresholdMb", "I"); 4576 gWebViewCoreFields.m_highUsageDeltaMb = env->GetFieldID(widget, "mHighUsageDeltaMb", "I"); 4577 4578 gWebViewCoreStaticMethods.m_isSupportedMediaMimeType = 4579 env->GetStaticMethodID(widget, "isSupportedMediaMimeType", "(Ljava/lang/String;)Z"); 4580 LOG_FATAL_IF(!gWebViewCoreStaticMethods.m_isSupportedMediaMimeType, 4581 "Could not find static method isSupportedMediaMimeType from WebViewCore"); 4582 4583 env->DeleteLocalRef(widget); 4584 4585 return jniRegisterNativeMethods(env, "android/webkit/WebViewCore", 4586 gJavaWebViewCoreMethods, NELEM(gJavaWebViewCoreMethods)); 4587} 4588 4589} /* namespace android */ 4590