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