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