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