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