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