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