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