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