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