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