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