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