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