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