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