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