WebViewCore.cpp revision 3d7cd084287f1dbc9fee600bf72af88c588a6429
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 3288bool WebViewCore::performMouseClick() 3289{ 3290 WebCore::PlatformMouseEvent mouseDown(m_mousePos, m_mousePos, WebCore::LeftButton, 3291 WebCore::MouseEventPressed, 1, false, false, false, false, 3292 WTF::currentTime()); 3293 // ignore the return from as it will return true if the hit point can trigger selection change 3294 m_mainFrame->eventHandler()->handleMousePressEvent(mouseDown); 3295 WebCore::PlatformMouseEvent mouseUp(m_mousePos, m_mousePos, WebCore::LeftButton, 3296 WebCore::MouseEventReleased, 1, false, false, false, false, 3297 WTF::currentTime()); 3298 bool handled = m_mainFrame->eventHandler()->handleMouseReleaseEvent(mouseUp); 3299 3300 WebCore::Node* focusNode = currentFocus(); 3301 initializeTextInput(focusNode, false); 3302 return handled; 3303} 3304 3305// Check for the "x-webkit-soft-keyboard" attribute. If it is there and 3306// set to hidden, do not show the soft keyboard. Node passed as a parameter 3307// must not be null. 3308static bool shouldSuppressKeyboard(const WebCore::Node* node) { 3309 ALOG_ASSERT(node, "node passed to shouldSuppressKeyboard cannot be null"); 3310 const NamedNodeMap* attributes = node->attributes(); 3311 if (!attributes) return false; 3312 size_t length = attributes->length(); 3313 for (size_t i = 0; i < length; i++) { 3314 const Attribute* a = attributes->attributeItem(i); 3315 if (a->localName() == "x-webkit-soft-keyboard" && a->value() == "hidden") 3316 return true; 3317 } 3318 return false; 3319} 3320 3321// Common code for both clicking with the trackball and touchUp 3322// Also used when typing into a non-focused textfield to give the textfield focus, 3323// in which case, 'fake' is set to true 3324bool WebViewCore::handleMouseClick(WebCore::Frame* framePtr, WebCore::Node* nodePtr, bool fake) 3325{ 3326 bool valid = !framePtr || validNode(m_mainFrame, framePtr, nodePtr); 3327 WebFrame* webFrame = WebFrame::getWebFrame(m_mainFrame); 3328 if (valid && nodePtr) { 3329 // Need to special case area tags because an image map could have an area element in the middle 3330 // so when attempting to get the default, the point chosen would be follow the wrong link. 3331 if (nodePtr->hasTagName(WebCore::HTMLNames::areaTag)) { 3332 nodePtr->dispatchSimulatedClick(0, true, true); 3333 return true; 3334 } 3335 } 3336 if (!valid || !framePtr) 3337 framePtr = m_mainFrame; 3338 WebCore::PlatformMouseEvent mouseDown(m_mousePos, m_mousePos, WebCore::LeftButton, 3339 WebCore::MouseEventPressed, 1, false, false, false, false, 3340 WTF::currentTime()); 3341 // ignore the return from as it will return true if the hit point can trigger selection change 3342 framePtr->eventHandler()->handleMousePressEvent(mouseDown); 3343 WebCore::PlatformMouseEvent mouseUp(m_mousePos, m_mousePos, WebCore::LeftButton, 3344 WebCore::MouseEventReleased, 1, false, false, false, false, 3345 WTF::currentTime()); 3346 bool handled = framePtr->eventHandler()->handleMouseReleaseEvent(mouseUp); 3347 3348 WebCore::Node* focusNode = currentFocus(); 3349 initializeTextInput(focusNode, fake); 3350 return handled; 3351} 3352 3353WebViewCore::InputType WebViewCore::getInputType(Node* node) 3354{ 3355 WebCore::RenderObject* renderer = node->renderer(); 3356 if (!renderer) 3357 return WebViewCore::NONE; 3358 if (renderer->isTextArea()) 3359 return WebViewCore::TEXT_AREA; 3360 3361 if (node->hasTagName(WebCore::HTMLNames::inputTag)) { 3362 HTMLInputElement* htmlInput = static_cast<HTMLInputElement*>(node); 3363 if (htmlInput->isPasswordField()) 3364 return WebViewCore::PASSWORD; 3365 if (htmlInput->isSearchField()) 3366 return WebViewCore::SEARCH; 3367 if (htmlInput->isEmailField()) 3368 return WebViewCore::EMAIL; 3369 if (htmlInput->isNumberField()) 3370 return WebViewCore::NUMBER; 3371 if (htmlInput->isTelephoneField()) 3372 return WebViewCore::TELEPHONE; 3373 if (htmlInput->isTextField()) 3374 return WebViewCore::NORMAL_TEXT_FIELD; 3375 } 3376 3377 if (node->isContentEditable()) 3378 return WebViewCore::TEXT_AREA; 3379 3380 return WebViewCore::NONE; 3381} 3382 3383int WebViewCore::getMaxLength(Node* node) 3384{ 3385 int maxLength = -1; 3386 if (node->hasTagName(WebCore::HTMLNames::inputTag)) { 3387 HTMLInputElement* htmlInput = static_cast<HTMLInputElement*>(node); 3388 maxLength = htmlInput->maxLength(); 3389 } 3390 return maxLength; 3391} 3392 3393String WebViewCore::getFieldName(Node* node) 3394{ 3395 String name; 3396 if (node->hasTagName(WebCore::HTMLNames::inputTag)) { 3397 HTMLInputElement* htmlInput = static_cast<HTMLInputElement*>(node); 3398 name = htmlInput->name(); 3399 } 3400 return name; 3401} 3402 3403bool WebViewCore::isSpellCheckEnabled(Node* node) 3404{ 3405 bool isEnabled = true; 3406 if (node->isElementNode()) { 3407 WebCore::Element* element = static_cast<WebCore::Element*>(node); 3408 isEnabled = element->isSpellCheckingEnabled(); 3409 } 3410 return isEnabled; 3411} 3412 3413bool WebViewCore::isAutoCompleteEnabled(Node* node) 3414{ 3415 bool isEnabled = false; 3416 if (node->hasTagName(WebCore::HTMLNames::inputTag)) { 3417 HTMLInputElement* htmlInput = static_cast<HTMLInputElement*>(node); 3418 isEnabled = htmlInput->autoComplete(); 3419 } 3420 return isEnabled; 3421} 3422 3423WebCore::IntRect WebViewCore::boundingRect(WebCore::Node* node, 3424 LayerAndroid* layer) 3425{ 3426 // Caret selection 3427 IntRect boundingRect; 3428 if (node) { 3429 RenderObject* render = node->renderer(); 3430 if (render && !render->isBody()) { 3431 IntPoint offset = convertGlobalContentToFrameContent(IntPoint(), 3432 node->document()->frame()); 3433 WebViewCore::layerToAbsoluteOffset(layer, offset); 3434 boundingRect = render->absoluteBoundingBoxRect(true); 3435 boundingRect.move(-offset.x(), -offset.y()); 3436 } 3437 } 3438 return boundingRect; 3439} 3440 3441jobject WebViewCore::createTextFieldInitData(Node* node) 3442{ 3443 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3444 TextFieldInitDataGlue* classDef = m_textFieldInitDataGlue; 3445 jclass clazz = env->FindClass("android/webkit/WebViewCore$TextFieldInitData"); 3446 jobject initData = env->NewObject(clazz, classDef->m_constructor); 3447 env->SetIntField(initData, classDef->m_fieldPointer, 3448 reinterpret_cast<int>(node)); 3449 env->SetObjectField(initData, classDef->m_text, 3450 wtfStringToJstring(env, getInputText(node), true)); 3451 env->SetIntField(initData, classDef->m_type, getInputType(node)); 3452 env->SetBooleanField(initData, classDef->m_isSpellCheckEnabled, 3453 isSpellCheckEnabled(node)); 3454 Document* document = node->document(); 3455 PlatformKeyboardEvent tab(AKEYCODE_TAB, 0, 0, false, false, false, false); 3456 PassRefPtr<KeyboardEvent> tabEvent = 3457 KeyboardEvent::create(tab, document->defaultView()); 3458 env->SetBooleanField(initData, classDef->m_isTextFieldNext, 3459 isTextInput(document->nextFocusableNode(node, tabEvent.get()))); 3460 env->SetBooleanField(initData, classDef->m_isTextFieldPrev, 3461 isTextInput(document->previousFocusableNode(node, tabEvent.get()))); 3462 env->SetBooleanField(initData, classDef->m_isAutoCompleteEnabled, 3463 isAutoCompleteEnabled(node)); 3464 env->SetObjectField(initData, classDef->m_name, 3465 wtfStringToJstring(env, getFieldName(node), false)); 3466 env->SetObjectField(initData, classDef->m_name, 3467 wtfStringToJstring(env, requestLabel(document->frame(), node), false)); 3468 env->SetIntField(initData, classDef->m_maxLength, getMaxLength(node)); 3469 LayerAndroid* layer = 0; 3470 int layerId = platformLayerIdFromNode(node, &layer); 3471 IntRect bounds = boundingRect(node, layer); 3472 env->SetObjectField(initData, classDef->m_nodeBounds, 3473 intRectToRect(env, bounds)); 3474 env->SetIntField(initData, classDef->m_nodeLayerId, layerId); 3475 IntRect contentRect; 3476 RenderTextControl* rtc = toRenderTextControl(node); 3477 if (rtc) { 3478 contentRect.setWidth(rtc->scrollWidth()); 3479 contentRect.setHeight(rtc->scrollHeight()); 3480 contentRect.move(-rtc->scrollLeft(), -rtc->scrollTop()); 3481 } 3482 env->SetObjectField(initData, classDef->m_contentRect, 3483 intRectToRect(env, contentRect)); 3484 return initData; 3485} 3486 3487void WebViewCore::initEditField(Node* node) 3488{ 3489 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3490 AutoJObject javaObject = m_javaGlue->object(env); 3491 if (!javaObject.get()) 3492 return; 3493 m_textGeneration = 0; 3494 int start = 0; 3495 int end = 0; 3496 getSelectionOffsets(node, start, end); 3497 SelectText* selectText = createSelectText(focusedFrame()->selection()->selection()); 3498 env->CallVoidMethod(javaObject.get(), m_javaGlue->m_initEditField, 3499 start, end, reinterpret_cast<int>(selectText), 3500 createTextFieldInitData(node)); 3501 checkException(env); 3502} 3503 3504void WebViewCore::popupReply(int index) 3505{ 3506 if (m_popupReply) { 3507 m_popupReply->replyInt(index); 3508 Release(m_popupReply); 3509 m_popupReply = 0; 3510 } 3511} 3512 3513void WebViewCore::popupReply(const int* array, int count) 3514{ 3515 if (m_popupReply) { 3516 m_popupReply->replyIntArray(array, count); 3517 Release(m_popupReply); 3518 m_popupReply = 0; 3519 } 3520} 3521 3522// This is a slightly modified Node::nextNodeConsideringAtomicNodes() with the 3523// extra constraint of limiting the search to inside a containing parent 3524WebCore::Node* nextNodeWithinParent(WebCore::Node* parent, WebCore::Node* start) 3525{ 3526 if (!isAtomicNode(start) && start->firstChild()) 3527 return start->firstChild(); 3528 if (start->nextSibling()) 3529 return start->nextSibling(); 3530 const Node *n = start; 3531 while (n && !n->nextSibling()) { 3532 n = n->parentNode(); 3533 if (n == parent) 3534 return 0; 3535 } 3536 if (n) 3537 return n->nextSibling(); 3538 return 0; 3539} 3540 3541void WebViewCore::initializeTextInput(WebCore::Node* node, bool fake) 3542{ 3543 if (node) { 3544 if (isTextInput(node)) { 3545 bool showKeyboard = true; 3546 initEditField(node); 3547 WebCore::RenderTextControl* rtc = toRenderTextControl(node); 3548 if (rtc && node->hasTagName(HTMLNames::inputTag)) { 3549 HTMLInputElement* inputElement = static_cast<HTMLInputElement*>(node); 3550 bool ime = !shouldSuppressKeyboard(node) && !inputElement->readOnly(); 3551 if (ime) { 3552#if ENABLE(WEB_AUTOFILL) 3553 if (rtc->isTextField()) { 3554 Page* page = node->document()->page(); 3555 EditorClient* editorClient = page->editorClient(); 3556 EditorClientAndroid* androidEditor = 3557 static_cast<EditorClientAndroid*>(editorClient); 3558 WebAutofill* autoFill = androidEditor->getAutofill(); 3559 autoFill->formFieldFocused(inputElement); 3560 } 3561#endif 3562 } else 3563 showKeyboard = false; 3564 } 3565 if (!fake) 3566 requestKeyboard(showKeyboard); 3567 } else if (!fake && !nodeIsPlugin(node)) { 3568 // not a text entry field, put away the keyboard. 3569 clearTextEntry(); 3570 } 3571 } else if (!fake) { 3572 // There is no focusNode, so the keyboard is not needed. 3573 clearTextEntry(); 3574 } 3575} 3576 3577void WebViewCore::focusNodeChanged(WebCore::Node* newFocus) 3578{ 3579 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3580 AutoJObject javaObject = m_javaGlue->object(env); 3581 if (!javaObject.get()) 3582 return; 3583 if (isTextInput(newFocus)) 3584 initializeTextInput(newFocus, true); 3585 HitTestResult focusHitResult; 3586 focusHitResult.setInnerNode(newFocus); 3587 focusHitResult.setInnerNonSharedNode(newFocus); 3588 if (newFocus && newFocus->isLink() && newFocus->isElementNode()) { 3589 focusHitResult.setURLElement(static_cast<Element*>(newFocus)); 3590 if (newFocus->hasChildNodes() && !newFocus->hasTagName(HTMLNames::imgTag)) { 3591 // Check to see if any of the children are images, and if so 3592 // set them as the innerNode and innerNonSharedNode 3593 // This will stop when it hits the first image. I'm not sure what 3594 // should be done in the case of multiple images inside one anchor... 3595 Node* nextNode = newFocus->firstChild(); 3596 bool found = false; 3597 while (nextNode) { 3598 if (nextNode->hasTagName(HTMLNames::imgTag)) { 3599 found = true; 3600 break; 3601 } 3602 nextNode = nextNodeWithinParent(newFocus, nextNode); 3603 } 3604 if (found) { 3605 focusHitResult.setInnerNode(nextNode); 3606 focusHitResult.setInnerNonSharedNode(nextNode); 3607 } 3608 } 3609 } 3610 AndroidHitTestResult androidHitTest(this, focusHitResult); 3611 jobject jHitTestObj = androidHitTest.createJavaObject(env); 3612 env->CallVoidMethod(javaObject.get(), m_javaGlue->m_focusNodeChanged, 3613 reinterpret_cast<int>(newFocus), jHitTestObj); 3614 env->DeleteLocalRef(jHitTestObj); 3615} 3616 3617void WebViewCore::addMessageToConsole(const WTF::String& message, unsigned int lineNumber, const WTF::String& sourceID, int msgLevel) { 3618 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3619 AutoJObject javaObject = m_javaGlue->object(env); 3620 if (!javaObject.get()) 3621 return; 3622 jstring jMessageStr = wtfStringToJstring(env, message); 3623 jstring jSourceIDStr = wtfStringToJstring(env, sourceID); 3624 env->CallVoidMethod(javaObject.get(), 3625 m_javaGlue->m_addMessageToConsole, jMessageStr, lineNumber, 3626 jSourceIDStr, msgLevel); 3627 env->DeleteLocalRef(jMessageStr); 3628 env->DeleteLocalRef(jSourceIDStr); 3629 checkException(env); 3630} 3631 3632void WebViewCore::jsAlert(const WTF::String& url, const WTF::String& text) 3633{ 3634 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3635 AutoJObject javaObject = m_javaGlue->object(env); 3636 if (!javaObject.get()) 3637 return; 3638 jstring jInputStr = wtfStringToJstring(env, text); 3639 jstring jUrlStr = wtfStringToJstring(env, url); 3640 env->CallVoidMethod(javaObject.get(), m_javaGlue->m_jsAlert, jUrlStr, jInputStr); 3641 env->DeleteLocalRef(jInputStr); 3642 env->DeleteLocalRef(jUrlStr); 3643 checkException(env); 3644} 3645 3646bool WebViewCore::exceededDatabaseQuota(const WTF::String& url, const WTF::String& databaseIdentifier, const unsigned long long currentQuota, unsigned long long estimatedSize) 3647{ 3648#if ENABLE(DATABASE) 3649 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3650 AutoJObject javaObject = m_javaGlue->object(env); 3651 if (!javaObject.get()) 3652 return false; 3653 jstring jDatabaseIdentifierStr = wtfStringToJstring(env, databaseIdentifier); 3654 jstring jUrlStr = wtfStringToJstring(env, url); 3655 env->CallVoidMethod(javaObject.get(), 3656 m_javaGlue->m_exceededDatabaseQuota, jUrlStr, 3657 jDatabaseIdentifierStr, currentQuota, estimatedSize); 3658 env->DeleteLocalRef(jDatabaseIdentifierStr); 3659 env->DeleteLocalRef(jUrlStr); 3660 checkException(env); 3661 return true; 3662#endif 3663} 3664 3665bool WebViewCore::reachedMaxAppCacheSize(const unsigned long long spaceNeeded) 3666{ 3667#if ENABLE(OFFLINE_WEB_APPLICATIONS) 3668 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3669 AutoJObject javaObject = m_javaGlue->object(env); 3670 if (!javaObject.get()) 3671 return false; 3672 env->CallVoidMethod(javaObject.get(), m_javaGlue->m_reachedMaxAppCacheSize, spaceNeeded); 3673 checkException(env); 3674 return true; 3675#endif 3676} 3677 3678void WebViewCore::populateVisitedLinks(WebCore::PageGroup* group) 3679{ 3680 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3681 AutoJObject javaObject = m_javaGlue->object(env); 3682 if (!javaObject.get()) 3683 return; 3684 m_groupForVisitedLinks = group; 3685 env->CallVoidMethod(javaObject.get(), m_javaGlue->m_populateVisitedLinks); 3686 checkException(env); 3687} 3688 3689void WebViewCore::geolocationPermissionsShowPrompt(const WTF::String& origin) 3690{ 3691 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3692 AutoJObject javaObject = m_javaGlue->object(env); 3693 if (!javaObject.get()) 3694 return; 3695 jstring originString = wtfStringToJstring(env, origin); 3696 env->CallVoidMethod(javaObject.get(), 3697 m_javaGlue->m_geolocationPermissionsShowPrompt, 3698 originString); 3699 env->DeleteLocalRef(originString); 3700 checkException(env); 3701} 3702 3703void WebViewCore::geolocationPermissionsHidePrompt() 3704{ 3705 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3706 AutoJObject javaObject = m_javaGlue->object(env); 3707 if (!javaObject.get()) 3708 return; 3709 env->CallVoidMethod(javaObject.get(), m_javaGlue->m_geolocationPermissionsHidePrompt); 3710 checkException(env); 3711} 3712 3713jobject WebViewCore::getDeviceMotionService() 3714{ 3715 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3716 AutoJObject javaObject = m_javaGlue->object(env); 3717 if (!javaObject.get()) 3718 return 0; 3719 jobject object = env->CallObjectMethod(javaObject.get(), m_javaGlue->m_getDeviceMotionService); 3720 checkException(env); 3721 return object; 3722} 3723 3724jobject WebViewCore::getDeviceOrientationService() 3725{ 3726 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3727 AutoJObject javaObject = m_javaGlue->object(env); 3728 if (!javaObject.get()) 3729 return 0; 3730 jobject object = env->CallObjectMethod(javaObject.get(), m_javaGlue->m_getDeviceOrientationService); 3731 checkException(env); 3732 return object; 3733} 3734 3735bool WebViewCore::jsConfirm(const WTF::String& url, const WTF::String& text) 3736{ 3737 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3738 AutoJObject javaObject = m_javaGlue->object(env); 3739 if (!javaObject.get()) 3740 return false; 3741 jstring jInputStr = wtfStringToJstring(env, text); 3742 jstring jUrlStr = wtfStringToJstring(env, url); 3743 jboolean result = env->CallBooleanMethod(javaObject.get(), m_javaGlue->m_jsConfirm, jUrlStr, jInputStr); 3744 env->DeleteLocalRef(jInputStr); 3745 env->DeleteLocalRef(jUrlStr); 3746 checkException(env); 3747 return result; 3748} 3749 3750bool WebViewCore::jsPrompt(const WTF::String& url, const WTF::String& text, const WTF::String& defaultValue, WTF::String& result) 3751{ 3752 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3753 AutoJObject javaObject = m_javaGlue->object(env); 3754 if (!javaObject.get()) 3755 return false; 3756 jstring jUrlStr = wtfStringToJstring(env, url); 3757 jstring jInputStr = wtfStringToJstring(env, text); 3758 jstring jDefaultStr = wtfStringToJstring(env, defaultValue); 3759 jstring returnVal = static_cast<jstring>(env->CallObjectMethod(javaObject.get(), m_javaGlue->m_jsPrompt, jUrlStr, jInputStr, jDefaultStr)); 3760 env->DeleteLocalRef(jUrlStr); 3761 env->DeleteLocalRef(jInputStr); 3762 env->DeleteLocalRef(jDefaultStr); 3763 checkException(env); 3764 3765 // If returnVal is null, it means that the user cancelled the dialog. 3766 if (!returnVal) 3767 return false; 3768 3769 result = jstringToWtfString(env, returnVal); 3770 env->DeleteLocalRef(returnVal); 3771 return true; 3772} 3773 3774bool WebViewCore::jsUnload(const WTF::String& url, const WTF::String& message) 3775{ 3776 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3777 AutoJObject javaObject = m_javaGlue->object(env); 3778 if (!javaObject.get()) 3779 return false; 3780 jstring jInputStr = wtfStringToJstring(env, message); 3781 jstring jUrlStr = wtfStringToJstring(env, url); 3782 jboolean result = env->CallBooleanMethod(javaObject.get(), m_javaGlue->m_jsUnload, jUrlStr, jInputStr); 3783 env->DeleteLocalRef(jInputStr); 3784 env->DeleteLocalRef(jUrlStr); 3785 checkException(env); 3786 return result; 3787} 3788 3789bool WebViewCore::jsInterrupt() 3790{ 3791 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3792 AutoJObject javaObject = m_javaGlue->object(env); 3793 if (!javaObject.get()) 3794 return false; 3795 jboolean result = env->CallBooleanMethod(javaObject.get(), m_javaGlue->m_jsInterrupt); 3796 checkException(env); 3797 return result; 3798} 3799 3800AutoJObject 3801WebViewCore::getJavaObject() 3802{ 3803 return m_javaGlue->object(JSC::Bindings::getJNIEnv()); 3804} 3805 3806jobject 3807WebViewCore::getWebViewJavaObject() 3808{ 3809 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3810 AutoJObject javaObject = m_javaGlue->object(env); 3811 if (!javaObject.get()) 3812 return 0; 3813 return env->CallObjectMethod(javaObject.get(), m_javaGlue->m_getWebView); 3814} 3815 3816RenderTextControl* WebViewCore::toRenderTextControl(Node* node) 3817{ 3818 RenderTextControl* rtc = 0; 3819 RenderObject* renderer = node->renderer(); 3820 if (renderer && renderer->isTextControl()) { 3821 rtc = WebCore::toRenderTextControl(renderer); 3822 } 3823 return rtc; 3824} 3825 3826void WebViewCore::getSelectionOffsets(Node* node, int& start, int& end) 3827{ 3828 RenderTextControl* rtc = toRenderTextControl(node); 3829 if (rtc) { 3830 start = rtc->selectionStart(); 3831 end = rtc->selectionEnd(); 3832 } else { 3833 // It must be content editable field. 3834 Document* document = node->document(); 3835 Frame* frame = document->frame(); 3836 SelectionController* selector = frame->selection(); 3837 Position selectionStart = selector->start(); 3838 Position selectionEnd = selector->end(); 3839 Position startOfNode = firstPositionInNode(node); 3840 RefPtr<Range> startRange = Range::create(document, startOfNode, 3841 selectionStart); 3842 start = TextIterator::rangeLength(startRange.get(), true); 3843 RefPtr<Range> endRange = Range::create(document, startOfNode, 3844 selectionEnd); 3845 end = TextIterator::rangeLength(endRange.get(), true); 3846 } 3847} 3848 3849String WebViewCore::getInputText(Node* node) 3850{ 3851 String text; 3852 WebCore::RenderTextControl* renderText = toRenderTextControl(node); 3853 if (renderText) 3854 text = renderText->text(); 3855 else { 3856 // It must be content editable field. 3857 Position start = firstPositionInNode(node); 3858 Position end = lastPositionInNode(node); 3859 VisibleSelection allEditableText(start, end); 3860 if (allEditableText.isRange()) 3861 text = allEditableText.firstRange()->text(); 3862 } 3863 return text; 3864} 3865 3866void WebViewCore::updateTextSelection() 3867{ 3868 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3869 AutoJObject javaObject = m_javaGlue->object(env); 3870 if (!javaObject.get()) 3871 return; 3872 VisibleSelection selection = focusedFrame()->selection()->selection(); 3873 int start = 0; 3874 int end = 0; 3875 if (selection.isCaretOrRange()) 3876 getSelectionOffsets(selection.start().anchorNode(), start, end); 3877 SelectText* selectText = createSelectText(selection); 3878 env->CallVoidMethod(javaObject.get(), 3879 m_javaGlue->m_updateTextSelection, reinterpret_cast<int>(currentFocus()), 3880 start, end, m_textGeneration, reinterpret_cast<int>(selectText)); 3881 checkException(env); 3882} 3883 3884void WebViewCore::updateTextSizeAndScroll(WebCore::Node* node) 3885{ 3886 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3887 AutoJObject javaObject = m_javaGlue->object(env); 3888 if (!javaObject.get()) 3889 return; 3890 RenderTextControl* rtc = toRenderTextControl(node); 3891 if (!rtc) 3892 return; 3893 int width = rtc->scrollWidth(); 3894 int height = rtc->contentHeight(); 3895 int scrollX = rtc->scrollLeft(); 3896 int scrollY = rtc->scrollTop(); 3897 env->CallVoidMethod(javaObject.get(), m_javaGlue->m_updateTextSizeAndScroll, 3898 reinterpret_cast<int>(node), width, height, scrollX, scrollY); 3899 checkException(env); 3900} 3901 3902void WebViewCore::updateTextfield(WebCore::Node* ptr, bool changeToPassword, 3903 const WTF::String& text) 3904{ 3905 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3906 AutoJObject javaObject = m_javaGlue->object(env); 3907 if (!javaObject.get()) 3908 return; 3909 if (m_blockTextfieldUpdates) 3910 return; 3911 if (changeToPassword) { 3912 env->CallVoidMethod(javaObject.get(), m_javaGlue->m_updateTextfield, 3913 (int) ptr, true, 0, m_textGeneration); 3914 checkException(env); 3915 return; 3916 } 3917 jstring string = wtfStringToJstring(env, text); 3918 env->CallVoidMethod(javaObject.get(), m_javaGlue->m_updateTextfield, 3919 (int) ptr, false, string, m_textGeneration); 3920 env->DeleteLocalRef(string); 3921 checkException(env); 3922} 3923 3924void WebViewCore::clearTextEntry() 3925{ 3926 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3927 AutoJObject javaObject = m_javaGlue->object(env); 3928 if (!javaObject.get()) 3929 return; 3930 env->CallVoidMethod(javaObject.get(), m_javaGlue->m_clearTextEntry); 3931} 3932 3933void WebViewCore::setBackgroundColor(SkColor c) 3934{ 3935 WebCore::FrameView* view = m_mainFrame->view(); 3936 if (!view) 3937 return; 3938 3939 // need (int) cast to find the right constructor 3940 WebCore::Color bcolor((int)SkColorGetR(c), (int)SkColorGetG(c), 3941 (int)SkColorGetB(c), (int)SkColorGetA(c)); 3942 view->setBaseBackgroundColor(bcolor); 3943 3944 // Background color of 0 indicates we want a transparent background 3945 if (c == 0) 3946 view->setTransparent(true); 3947} 3948 3949jclass WebViewCore::getPluginClass(const WTF::String& libName, const char* className) 3950{ 3951 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3952 AutoJObject javaObject = m_javaGlue->object(env); 3953 if (!javaObject.get()) 3954 return 0; 3955 3956 jstring libString = wtfStringToJstring(env, libName); 3957 jstring classString = env->NewStringUTF(className); 3958 jobject pluginClass = env->CallObjectMethod(javaObject.get(), 3959 m_javaGlue->m_getPluginClass, 3960 libString, classString); 3961 checkException(env); 3962 3963 // cleanup unneeded local JNI references 3964 env->DeleteLocalRef(libString); 3965 env->DeleteLocalRef(classString); 3966 3967 if (pluginClass != 0) { 3968 return static_cast<jclass>(pluginClass); 3969 } else { 3970 return 0; 3971 } 3972} 3973 3974void WebViewCore::showFullScreenPlugin(jobject childView, int32_t orientation, NPP npp) 3975{ 3976 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3977 AutoJObject javaObject = m_javaGlue->object(env); 3978 if (!javaObject.get()) 3979 return; 3980 3981 env->CallVoidMethod(javaObject.get(), 3982 m_javaGlue->m_showFullScreenPlugin, 3983 childView, orientation, reinterpret_cast<int>(npp)); 3984 checkException(env); 3985} 3986 3987void WebViewCore::hideFullScreenPlugin() 3988{ 3989 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3990 AutoJObject javaObject = m_javaGlue->object(env); 3991 if (!javaObject.get()) 3992 return; 3993 env->CallVoidMethod(javaObject.get(), m_javaGlue->m_hideFullScreenPlugin); 3994 checkException(env); 3995} 3996 3997jobject WebViewCore::createSurface(jobject view) 3998{ 3999 JNIEnv* env = JSC::Bindings::getJNIEnv(); 4000 AutoJObject javaObject = m_javaGlue->object(env); 4001 if (!javaObject.get()) 4002 return 0; 4003 jobject result = env->CallObjectMethod(javaObject.get(), m_javaGlue->m_createSurface, view); 4004 checkException(env); 4005 return result; 4006} 4007 4008jobject WebViewCore::addSurface(jobject view, 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 0; 4014 jobject result = env->CallObjectMethod(javaObject.get(), 4015 m_javaGlue->m_addSurface, 4016 view, x, y, width, height); 4017 checkException(env); 4018 return result; 4019} 4020 4021void WebViewCore::updateSurface(jobject childView, int x, int y, int width, int height) 4022{ 4023 JNIEnv* env = JSC::Bindings::getJNIEnv(); 4024 AutoJObject javaObject = m_javaGlue->object(env); 4025 if (!javaObject.get()) 4026 return; 4027 env->CallVoidMethod(javaObject.get(), 4028 m_javaGlue->m_updateSurface, childView, 4029 x, y, width, height); 4030 checkException(env); 4031} 4032 4033void WebViewCore::destroySurface(jobject childView) 4034{ 4035 JNIEnv* env = JSC::Bindings::getJNIEnv(); 4036 AutoJObject javaObject = m_javaGlue->object(env); 4037 if (!javaObject.get()) 4038 return; 4039 env->CallVoidMethod(javaObject.get(), m_javaGlue->m_destroySurface, childView); 4040 checkException(env); 4041} 4042 4043jobject WebViewCore::getContext() 4044{ 4045 JNIEnv* env = JSC::Bindings::getJNIEnv(); 4046 AutoJObject javaObject = m_javaGlue->object(env); 4047 if (!javaObject.get()) 4048 return 0; 4049 4050 jobject result = env->CallObjectMethod(javaObject.get(), m_javaGlue->m_getContext); 4051 checkException(env); 4052 return result; 4053} 4054 4055void WebViewCore::keepScreenOn(bool screenOn) { 4056 if ((screenOn && m_screenOnCounter == 0) || (!screenOn && m_screenOnCounter == 1)) { 4057 JNIEnv* env = JSC::Bindings::getJNIEnv(); 4058 AutoJObject javaObject = m_javaGlue->object(env); 4059 if (!javaObject.get()) 4060 return; 4061 env->CallVoidMethod(javaObject.get(), m_javaGlue->m_keepScreenOn, screenOn); 4062 checkException(env); 4063 } 4064 4065 // update the counter 4066 if (screenOn) 4067 m_screenOnCounter++; 4068 else if (m_screenOnCounter > 0) 4069 m_screenOnCounter--; 4070} 4071 4072void WebViewCore::showRect(int left, int top, int width, int height, 4073 int contentWidth, int contentHeight, float xPercentInDoc, 4074 float xPercentInView, float yPercentInDoc, float yPercentInView) 4075{ 4076 JNIEnv* env = JSC::Bindings::getJNIEnv(); 4077 AutoJObject javaObject = m_javaGlue->object(env); 4078 if (!javaObject.get()) 4079 return; 4080 env->CallVoidMethod(javaObject.get(), m_javaGlue->m_showRect, 4081 left, top, width, height, contentWidth, contentHeight, 4082 xPercentInDoc, xPercentInView, yPercentInDoc, yPercentInView); 4083 checkException(env); 4084} 4085 4086void WebViewCore::centerFitRect(int x, int y, int width, int height) 4087{ 4088 JNIEnv* env = JSC::Bindings::getJNIEnv(); 4089 AutoJObject javaObject = m_javaGlue->object(env); 4090 if (!javaObject.get()) 4091 return; 4092 env->CallVoidMethod(javaObject.get(), m_javaGlue->m_centerFitRect, x, y, width, height); 4093 checkException(env); 4094} 4095 4096void WebViewCore::setScrollbarModes(ScrollbarMode horizontalMode, ScrollbarMode verticalMode) 4097{ 4098 JNIEnv* env = JSC::Bindings::getJNIEnv(); 4099 AutoJObject javaObject = m_javaGlue->object(env); 4100 if (!javaObject.get()) 4101 return; 4102 env->CallVoidMethod(javaObject.get(), m_javaGlue->m_setScrollbarModes, horizontalMode, verticalMode); 4103 checkException(env); 4104} 4105 4106void WebViewCore::notifyWebAppCanBeInstalled() 4107{ 4108 JNIEnv* env = JSC::Bindings::getJNIEnv(); 4109 AutoJObject javaObject = m_javaGlue->object(env); 4110 if (!javaObject.get()) 4111 return; 4112 env->CallVoidMethod(javaObject.get(), m_javaGlue->m_setInstallableWebApp); 4113 checkException(env); 4114} 4115 4116#if ENABLE(VIDEO) 4117void WebViewCore::enterFullscreenForVideoLayer(int layerId, const WTF::String& url) 4118{ 4119 JNIEnv* env = JSC::Bindings::getJNIEnv(); 4120 AutoJObject javaObject = m_javaGlue->object(env); 4121 if (!javaObject.get()) 4122 return; 4123 jstring jUrlStr = wtfStringToJstring(env, url); 4124 env->CallVoidMethod(javaObject.get(), m_javaGlue->m_enterFullscreenForVideoLayer, layerId, jUrlStr); 4125 m_fullscreenVideoMode = true; 4126 checkException(env); 4127} 4128 4129void WebViewCore::exitFullscreenVideo() 4130{ 4131 JNIEnv* env = JSC::Bindings::getJNIEnv(); 4132 AutoJObject javaObject = m_javaGlue->object(env); 4133 if (!javaObject.get()) 4134 return; 4135 if (m_fullscreenVideoMode) { 4136 env->CallVoidMethod(javaObject.get(), m_javaGlue->m_exitFullscreenVideo); 4137 m_fullscreenVideoMode = false; 4138 } 4139 checkException(env); 4140} 4141#endif 4142 4143void WebViewCore::setWebTextViewAutoFillable(int queryId, const string16& previewSummary) 4144{ 4145#if ENABLE(WEB_AUTOFILL) 4146 JNIEnv* env = JSC::Bindings::getJNIEnv(); 4147 AutoJObject javaObject = m_javaGlue->object(env); 4148 if (!javaObject.get()) 4149 return; 4150 jstring preview = env->NewString(previewSummary.data(), previewSummary.length()); 4151 env->CallVoidMethod(javaObject.get(), m_javaGlue->m_setWebTextViewAutoFillable, queryId, preview); 4152 env->DeleteLocalRef(preview); 4153#endif 4154} 4155 4156bool WebViewCore::drawIsPaused() const 4157{ 4158 // returning true says scrollview should be offscreen, which pauses 4159 // gifs. because this is not again queried when we stop scrolling, we don't 4160 // use the stopping currently. 4161 return false; 4162} 4163 4164void WebViewCore::setWebRequestContextUserAgent() 4165{ 4166 // We cannot create a WebRequestContext, because we might not know it this is a private tab or not yet 4167 if (m_webRequestContext) 4168 m_webRequestContext->setUserAgent(WebFrame::getWebFrame(m_mainFrame)->userAgentForURL(0)); // URL not used 4169} 4170 4171void WebViewCore::setWebRequestContextCacheMode(int cacheMode) 4172{ 4173 m_cacheMode = cacheMode; 4174 // We cannot create a WebRequestContext, because we might not know it this is a private tab or not yet 4175 if (!m_webRequestContext) 4176 return; 4177 4178 m_webRequestContext->setCacheMode(cacheMode); 4179} 4180 4181WebRequestContext* WebViewCore::webRequestContext() 4182{ 4183 if (!m_webRequestContext) { 4184 Settings* settings = mainFrame()->settings(); 4185 m_webRequestContext = new WebRequestContext(settings && settings->privateBrowsingEnabled()); 4186 setWebRequestContextUserAgent(); 4187 setWebRequestContextCacheMode(m_cacheMode); 4188 } 4189 return m_webRequestContext.get(); 4190} 4191 4192void WebViewCore::scrollRenderLayer(int layer, const SkRect& rect) 4193{ 4194#if USE(ACCELERATED_COMPOSITING) 4195 GraphicsLayerAndroid* root = graphicsRootLayer(); 4196 if (!root) 4197 return; 4198 4199 LayerAndroid* layerAndroid = root->platformLayer(); 4200 if (!layerAndroid) 4201 return; 4202 4203 LayerAndroid* target = layerAndroid->findById(layer); 4204 if (!target) 4205 return; 4206 4207 RenderLayer* owner = target->owningLayer(); 4208 if (!owner) 4209 return; 4210 4211 if (owner->isRootLayer()) { 4212 FrameView* view = owner->renderer()->frame()->view(); 4213 IntPoint pt(rect.fLeft, rect.fTop); 4214 view->setScrollPosition(pt); 4215 } else 4216 owner->scrollToOffset(rect.fLeft, rect.fTop); 4217#endif 4218} 4219 4220Vector<VisibleSelection> WebViewCore::getTextRanges( 4221 int startX, int startY, int endX, int endY) 4222{ 4223 // These are the positions of the selection handles, 4224 // which reside below the line that they are selecting. 4225 // Use the vertical position higher, which will include 4226 // the selected text. 4227 startY--; 4228 endY--; 4229 VisiblePosition startSelect = visiblePositionForContentPoint(startX, startY); 4230 VisiblePosition endSelect = visiblePositionForContentPoint(endX, endY); 4231 Position start = startSelect.deepEquivalent(); 4232 Position end = endSelect.deepEquivalent(); 4233 Vector<VisibleSelection> ranges; 4234 if (!start.isNull() && !end.isNull()) { 4235 if (comparePositions(start, end) > 0) { 4236 swap(start, end); // RTL start/end positions may be swapped 4237 } 4238 Position nextRangeStart = start; 4239 Position previousRangeEnd; 4240 do { 4241 VisibleSelection selection(nextRangeStart, end); 4242 ranges.append(selection); 4243 previousRangeEnd = selection.end(); 4244 nextRangeStart = nextCandidate(previousRangeEnd); 4245 } while (comparePositions(previousRangeEnd, end) < 0); 4246 } 4247 return ranges; 4248} 4249 4250void WebViewCore::deleteText(int startX, int startY, int endX, int endY) 4251{ 4252 Vector<VisibleSelection> ranges = 4253 getTextRanges(startX, startY, endX, endY); 4254 4255 EditorClientAndroid* client = static_cast<EditorClientAndroid*>( 4256 m_mainFrame->editor()->client()); 4257 client->setUiGeneratedSelectionChange(true); 4258 4259 SelectionController* selector = m_mainFrame->selection(); 4260 for (size_t i = 0; i < ranges.size(); i++) { 4261 const VisibleSelection& selection = ranges[i]; 4262 if (selection.isContentEditable()) { 4263 selector->setSelection(selection, CharacterGranularity); 4264 Document* document = selection.start().anchorNode()->document(); 4265 WebCore::TypingCommand::deleteSelection(document, 0); 4266 } 4267 } 4268 client->setUiGeneratedSelectionChange(false); 4269} 4270 4271void WebViewCore::insertText(const WTF::String &text) 4272{ 4273 WebCore::Node* focus = currentFocus(); 4274 if (!focus || !isTextInput(focus)) 4275 return; 4276 4277 Document* document = focus->document(); 4278 4279 EditorClientAndroid* client = static_cast<EditorClientAndroid*>( 4280 m_mainFrame->editor()->client()); 4281 if (!client) 4282 return; 4283 client->setUiGeneratedSelectionChange(true); 4284 WebCore::TypingCommand::insertText(document, text, 4285 TypingCommand::PreventSpellChecking); 4286 client->setUiGeneratedSelectionChange(false); 4287} 4288 4289void WebViewCore::resetFindOnPage() 4290{ 4291 m_searchText.truncate(0); 4292 m_matchCount = 0; 4293 m_activeMatchIndex = 0; 4294 m_activeMatch = 0; 4295} 4296 4297int WebViewCore::findTextOnPage(const WTF::String &text) 4298{ 4299 resetFindOnPage(); // reset even if parameters are bad 4300 4301 WebCore::Frame* frame = m_mainFrame; 4302 if (!frame) 4303 return 0; 4304 4305 m_searchText = text; 4306 FindOptions findOptions = WebCore::CaseInsensitive; 4307 4308 do { 4309 frame->document()->markers()->removeMarkers(DocumentMarker::TextMatch); 4310 m_matchCount += frame->editor()->countMatchesForText(text, findOptions, 4311 0, true); 4312 frame->editor()->setMarkedTextMatchesAreHighlighted(true); 4313 frame = frame->tree()->traverseNextWithWrap(false); 4314 } while (frame); 4315 m_activeMatchIndex = m_matchCount - 1; // prime first findNext 4316 return m_matchCount; 4317} 4318 4319int WebViewCore::findNextOnPage(bool forward) 4320{ 4321 if (!m_mainFrame) 4322 return -1; 4323 if (!m_matchCount) 4324 return -1; 4325 4326 EditorClientAndroid* client = static_cast<EditorClientAndroid*>( 4327 m_mainFrame->editor()->client()); 4328 client->setUiGeneratedSelectionChange(true); 4329 4330 // Clear previous active match. 4331 if (m_activeMatch) { 4332 m_mainFrame->document()->markers()->setMarkersActive( 4333 m_activeMatch.get(), false); 4334 } 4335 4336 FindOptions findOptions = WebCore::CaseInsensitive 4337 | WebCore::StartInSelection | WebCore::WrapAround; 4338 if (!forward) 4339 findOptions |= WebCore::Backwards; 4340 4341 // Start from the previous active match. 4342 if (m_activeMatch) { 4343 m_mainFrame->selection()->setSelection(m_activeMatch.get()); 4344 } 4345 4346 bool found = m_mainFrame->editor()->findString(m_searchText, findOptions); 4347 if (found) { 4348 VisibleSelection selection(m_mainFrame->selection()->selection()); 4349 if (selection.isNone() || selection.start() == selection.end()) { 4350 // Temporary workaround for findString() refusing to select text 4351 // marked "-webkit-user-select: none". 4352 m_activeMatchIndex = 0; 4353 m_activeMatch = 0; 4354 } else { 4355 // Mark current match "active". 4356 if (forward) { 4357 ++m_activeMatchIndex; 4358 if (m_activeMatchIndex == m_matchCount) 4359 m_activeMatchIndex = 0; 4360 } else { 4361 if (m_activeMatchIndex == 0) 4362 m_activeMatchIndex = m_matchCount; 4363 --m_activeMatchIndex; 4364 } 4365 m_activeMatch = selection.firstRange(); 4366 m_mainFrame->document()->markers()->setMarkersActive( 4367 m_activeMatch.get(), true); 4368 m_mainFrame->selection()->revealSelection( 4369 ScrollAlignment::alignCenterIfNeeded, true); 4370 } 4371 } 4372 4373 // Clear selection so it doesn't display. 4374 m_mainFrame->selection()->clear(); 4375 client->setUiGeneratedSelectionChange(false); 4376 return m_activeMatchIndex; 4377} 4378 4379String WebViewCore::getText(int startX, int startY, int endX, int endY) 4380{ 4381 String text; 4382 4383 Vector<VisibleSelection> ranges = 4384 getTextRanges(startX, startY, endX, endY); 4385 4386 for (size_t i = 0; i < ranges.size(); i++) { 4387 const VisibleSelection& selection = ranges[i]; 4388 if (selection.isRange()) { 4389 PassRefPtr<Range> range = selection.firstRange(); 4390 String textInRange = range->text(); 4391 if (textInRange.length() > 0) { 4392 if (text.length() > 0) 4393 text.append('\n'); 4394 text.append(textInRange); 4395 } 4396 } 4397 } 4398 4399 return text; 4400} 4401 4402/** 4403 * Read the persistent locale. 4404 */ 4405void WebViewCore::getLocale(String& language, String& region) 4406{ 4407 char propLang[PROPERTY_VALUE_MAX], propRegn[PROPERTY_VALUE_MAX]; 4408 4409 property_get("persist.sys.language", propLang, ""); 4410 property_get("persist.sys.country", propRegn, ""); 4411 if (*propLang == 0 && *propRegn == 0) { 4412 /* Set to ro properties, default is en_US */ 4413 property_get("ro.product.locale.language", propLang, "en"); 4414 property_get("ro.product.locale.region", propRegn, "US"); 4415 } 4416 language = String(propLang, 2); 4417 region = String(propRegn, 2); 4418} 4419 4420void WebViewCore::updateLocale() 4421{ 4422 static String prevLang; 4423 static String prevRegn; 4424 String language; 4425 String region; 4426 4427 getLocale(language, region); 4428 4429 if ((language != prevLang) || (region != prevRegn)) { 4430 prevLang = language; 4431 prevRegn = region; 4432 GlyphPageTreeNode::resetRoots(); 4433 fontCache()->invalidate(); 4434 } 4435} 4436 4437//---------------------------------------------------------------------- 4438// Native JNI methods 4439//---------------------------------------------------------------------- 4440static void RevealSelection(JNIEnv* env, jobject obj, jint nativeClass) 4441{ 4442 reinterpret_cast<WebViewCore*>(nativeClass)->revealSelection(); 4443} 4444 4445static jstring RequestLabel(JNIEnv* env, jobject obj, jint nativeClass, 4446 int framePointer, int nodePointer) 4447{ 4448 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4449 return wtfStringToJstring(env, viewImpl->requestLabel( 4450 (WebCore::Frame*) framePointer, (WebCore::Node*) nodePointer)); 4451} 4452 4453static void ClearContent(JNIEnv* env, jobject obj, jint nativeClass) 4454{ 4455 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4456 viewImpl->clearContent(); 4457} 4458 4459static void SetSize(JNIEnv* env, jobject obj, jint nativeClass, jint width, 4460 jint height, jint textWrapWidth, jfloat scale, jint screenWidth, 4461 jint screenHeight, jint anchorX, jint anchorY, jboolean ignoreHeight) 4462{ 4463 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4464 ALOGV("webviewcore::nativeSetSize(%u %u)\n viewImpl: %p", (unsigned)width, (unsigned)height, viewImpl); 4465 ALOG_ASSERT(viewImpl, "viewImpl not set in nativeSetSize"); 4466 viewImpl->setSizeScreenWidthAndScale(width, height, textWrapWidth, scale, 4467 screenWidth, screenHeight, anchorX, anchorY, ignoreHeight); 4468} 4469 4470static void SetScrollOffset(JNIEnv* env, jobject obj, jint nativeClass, 4471 jboolean sendScrollEvent, jint x, jint y) 4472{ 4473 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4474 ALOG_ASSERT(viewImpl, "need viewImpl"); 4475 4476 viewImpl->setScrollOffset(sendScrollEvent, x, y); 4477} 4478 4479static void SetGlobalBounds(JNIEnv* env, jobject obj, jint nativeClass, 4480 jint x, jint y, jint h, jint v) 4481{ 4482 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4483 ALOG_ASSERT(viewImpl, "need viewImpl"); 4484 4485 viewImpl->setGlobalBounds(x, y, h, v); 4486} 4487 4488static jboolean Key(JNIEnv* env, jobject obj, jint nativeClass, jint keyCode, 4489 jint unichar, jint repeatCount, jboolean isShift, jboolean isAlt, 4490 jboolean isSym, jboolean isDown) 4491{ 4492 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4493 return viewImpl->key(PlatformKeyboardEvent(keyCode, 4494 unichar, repeatCount, isDown, isShift, isAlt, isSym)); 4495} 4496 4497static void Click(JNIEnv* env, jobject obj, jint nativeClass, int framePtr, 4498 int nodePtr, jboolean fake) 4499{ 4500 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4501 ALOG_ASSERT(viewImpl, "viewImpl not set in Click"); 4502 4503 viewImpl->click(reinterpret_cast<WebCore::Frame*>(framePtr), 4504 reinterpret_cast<WebCore::Node*>(nodePtr), fake); 4505} 4506 4507static void ContentInvalidateAll(JNIEnv* env, jobject obj, jint nativeClass) 4508{ 4509 reinterpret_cast<WebViewCore*>(nativeClass)->contentInvalidateAll(); 4510} 4511 4512static void DeleteSelection(JNIEnv* env, jobject obj, jint nativeClass, 4513 jint start, jint end, jint textGeneration) 4514{ 4515 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4516 viewImpl->deleteSelection(start, end, textGeneration); 4517} 4518 4519static void SetSelection(JNIEnv* env, jobject obj, jint nativeClass, 4520 jint start, jint end) 4521{ 4522 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4523 viewImpl->setSelection(start, end); 4524} 4525 4526static jstring ModifySelection(JNIEnv* env, jobject obj, jint nativeClass, 4527 jint direction, jint granularity) 4528{ 4529 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4530 String selectionString = viewImpl->modifySelection(direction, granularity); 4531 return wtfStringToJstring(env, selectionString); 4532} 4533 4534static void ReplaceTextfieldText(JNIEnv* env, jobject obj, jint nativeClass, 4535 jint oldStart, jint oldEnd, jstring replace, jint start, jint end, 4536 jint textGeneration) 4537{ 4538 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4539 WTF::String webcoreString = jstringToWtfString(env, replace); 4540 viewImpl->replaceTextfieldText(oldStart, 4541 oldEnd, webcoreString, start, end, textGeneration); 4542} 4543 4544static void PassToJs(JNIEnv* env, jobject obj, jint nativeClass, 4545 jint generation, jstring currentText, jint keyCode, 4546 jint keyValue, jboolean down, jboolean cap, jboolean fn, jboolean sym) 4547{ 4548 WTF::String current = jstringToWtfString(env, currentText); 4549 reinterpret_cast<WebViewCore*>(nativeClass)->passToJs(generation, current, 4550 PlatformKeyboardEvent(keyCode, keyValue, 0, down, cap, fn, sym)); 4551} 4552 4553static void ScrollFocusedTextInput(JNIEnv* env, jobject obj, jint nativeClass, 4554 jfloat xPercent, jint y) 4555{ 4556 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4557 viewImpl->scrollFocusedTextInput(xPercent, y); 4558} 4559 4560static void SetFocusControllerActive(JNIEnv* env, jobject obj, jint nativeClass, 4561 jboolean active) 4562{ 4563 ALOGV("webviewcore::nativeSetFocusControllerActive()\n"); 4564 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4565 ALOG_ASSERT(viewImpl, "viewImpl not set in nativeSetFocusControllerActive"); 4566 viewImpl->setFocusControllerActive(active); 4567} 4568 4569static void SaveDocumentState(JNIEnv* env, jobject obj, jint nativeClass) 4570{ 4571 ALOGV("webviewcore::nativeSaveDocumentState()\n"); 4572 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4573 ALOG_ASSERT(viewImpl, "viewImpl not set in nativeSaveDocumentState"); 4574 viewImpl->saveDocumentState(viewImpl->focusedFrame()); 4575} 4576 4577void WebViewCore::addVisitedLink(const UChar* string, int length) 4578{ 4579 if (m_groupForVisitedLinks) 4580 m_groupForVisitedLinks->addVisitedLink(string, length); 4581} 4582 4583static bool UpdateLayers(JNIEnv* env, jobject obj, jint nativeClass, 4584 jint jbaseLayer) 4585{ 4586 WebViewCore* viewImpl = (WebViewCore*) nativeClass; 4587 BaseLayerAndroid* baseLayer = (BaseLayerAndroid*) jbaseLayer; 4588 if (baseLayer) { 4589 LayerAndroid* root = static_cast<LayerAndroid*>(baseLayer->getChild(0)); 4590 if (root) 4591 return viewImpl->updateLayers(root); 4592 } 4593 return true; 4594} 4595 4596static void NotifyAnimationStarted(JNIEnv* env, jobject obj, jint nativeClass) 4597{ 4598 WebViewCore* viewImpl = (WebViewCore*) nativeClass; 4599 viewImpl->notifyAnimationStarted(); 4600} 4601 4602static jint RecordContent(JNIEnv* env, jobject obj, jint nativeClass, 4603 jobject region, jobject pt) 4604{ 4605 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4606 SkRegion* nativeRegion = GraphicsJNI::getNativeRegion(env, region); 4607 SkIPoint nativePt; 4608 BaseLayerAndroid* result = viewImpl->recordContent(nativeRegion, &nativePt); 4609 GraphicsJNI::ipoint_to_jpoint(nativePt, env, pt); 4610 return reinterpret_cast<jint>(result); 4611} 4612 4613static void SplitContent(JNIEnv* env, jobject obj, jint nativeClass, 4614 jint content) 4615{ 4616 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4617 viewImpl->splitContent(reinterpret_cast<PictureSet*>(content)); 4618} 4619 4620static void SendListBoxChoice(JNIEnv* env, jobject obj, jint nativeClass, 4621 jint choice) 4622{ 4623 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4624 ALOG_ASSERT(viewImpl, "viewImpl not set in nativeSendListBoxChoice"); 4625 viewImpl->popupReply(choice); 4626} 4627 4628// Set aside a predetermined amount of space in which to place the listbox 4629// choices, to avoid unnecessary allocations. 4630// The size here is arbitrary. We want the size to be at least as great as the 4631// number of items in the average multiple-select listbox. 4632#define PREPARED_LISTBOX_STORAGE 10 4633 4634static void SendListBoxChoices(JNIEnv* env, jobject obj, jint nativeClass, 4635 jbooleanArray jArray, jint size) 4636{ 4637 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4638 ALOG_ASSERT(viewImpl, "viewImpl not set in nativeSendListBoxChoices"); 4639 jboolean* ptrArray = env->GetBooleanArrayElements(jArray, 0); 4640 SkAutoSTMalloc<PREPARED_LISTBOX_STORAGE, int> storage(size); 4641 int* array = storage.get(); 4642 int count = 0; 4643 for (int i = 0; i < size; i++) { 4644 if (ptrArray[i]) { 4645 array[count++] = i; 4646 } 4647 } 4648 env->ReleaseBooleanArrayElements(jArray, ptrArray, JNI_ABORT); 4649 viewImpl->popupReply(array, count); 4650} 4651 4652// TODO: Move this to WebView.cpp since it is only needed there 4653static jstring FindAddress(JNIEnv* env, jobject obj, jstring addr, 4654 jboolean caseInsensitive) 4655{ 4656 if (!addr) 4657 return 0; 4658 int length = env->GetStringLength(addr); 4659 if (!length) 4660 return 0; 4661 const jchar* addrChars = env->GetStringChars(addr, 0); 4662 size_t start, end; 4663 AddressDetector detector; 4664 bool success = detector.FindContent(addrChars, addrChars + length, &start, &end); 4665 jstring ret = 0; 4666 if (success) 4667 ret = env->NewString(addrChars + start, end - start); 4668 env->ReleaseStringChars(addr, addrChars); 4669 return ret; 4670} 4671 4672static jboolean HandleTouchEvent(JNIEnv* env, jobject obj, jint nativeClass, 4673 jint action, jintArray idArray, jintArray xArray, jintArray yArray, 4674 jint count, jint actionIndex, jint metaState) 4675{ 4676 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4677 ALOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); 4678 jint* ptrIdArray = env->GetIntArrayElements(idArray, 0); 4679 jint* ptrXArray = env->GetIntArrayElements(xArray, 0); 4680 jint* ptrYArray = env->GetIntArrayElements(yArray, 0); 4681 Vector<int> ids(count); 4682 Vector<IntPoint> points(count); 4683 for (int c = 0; c < count; c++) { 4684 ids[c] = ptrIdArray[c]; 4685 points[c].setX(ptrXArray[c]); 4686 points[c].setY(ptrYArray[c]); 4687 } 4688 env->ReleaseIntArrayElements(idArray, ptrIdArray, JNI_ABORT); 4689 env->ReleaseIntArrayElements(xArray, ptrXArray, JNI_ABORT); 4690 env->ReleaseIntArrayElements(yArray, ptrYArray, JNI_ABORT); 4691 4692 return viewImpl->handleTouchEvent(action, ids, points, actionIndex, metaState); 4693} 4694 4695static void TouchUp(JNIEnv* env, jobject obj, jint nativeClass, 4696 jint touchGeneration, jint frame, jint node, jint x, jint y) 4697{ 4698 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4699 ALOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); 4700 viewImpl->touchUp(touchGeneration, 4701 (WebCore::Frame*) frame, (WebCore::Node*) node, x, y); 4702} 4703 4704static bool MouseClick(JNIEnv* env, jobject obj, jint nativeClass) 4705{ 4706 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4707 return viewImpl->performMouseClick(); 4708} 4709 4710static jstring RetrieveHref(JNIEnv* env, jobject obj, jint nativeClass, 4711 jint x, jint y) 4712{ 4713 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4714 ALOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); 4715 WTF::String result = viewImpl->retrieveHref(x, y); 4716 if (!result.isEmpty()) 4717 return wtfStringToJstring(env, result); 4718 return 0; 4719} 4720 4721static jstring RetrieveAnchorText(JNIEnv* env, jobject obj, jint nativeClass, 4722 jint x, jint y) 4723{ 4724 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4725 ALOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); 4726 WTF::String result = viewImpl->retrieveAnchorText(x, y); 4727 if (!result.isEmpty()) 4728 return wtfStringToJstring(env, result); 4729 return 0; 4730} 4731 4732static jstring RetrieveImageSource(JNIEnv* env, jobject obj, jint nativeClass, 4733 jint x, jint y) 4734{ 4735 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4736 WTF::String result = viewImpl->retrieveImageSource(x, y); 4737 return !result.isEmpty() ? wtfStringToJstring(env, result) : 0; 4738} 4739 4740static void MoveMouse(JNIEnv* env, jobject obj, jint nativeClass, jint x, jint y) 4741{ 4742 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4743 ALOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); 4744 viewImpl->moveMouse(x, y); 4745} 4746 4747static jint GetContentMinPrefWidth(JNIEnv* env, jobject obj, jint nativeClass) 4748{ 4749 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4750 ALOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); 4751 4752 WebCore::Frame* frame = viewImpl->mainFrame(); 4753 if (frame) { 4754 WebCore::Document* document = frame->document(); 4755 if (document) { 4756 WebCore::RenderObject* renderer = document->renderer(); 4757 if (renderer && renderer->isRenderView()) { 4758 return renderer->minPreferredLogicalWidth(); 4759 } 4760 } 4761 } 4762 return 0; 4763} 4764 4765static void SetViewportSettingsFromNative(JNIEnv* env, jobject obj, 4766 jint nativeClass) 4767{ 4768 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4769 ALOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); 4770 4771 WebCore::Settings* s = viewImpl->mainFrame()->page()->settings(); 4772 if (!s) 4773 return; 4774 4775#ifdef ANDROID_META_SUPPORT 4776 env->SetIntField(obj, gWebViewCoreFields.m_viewportWidth, s->viewportWidth()); 4777 env->SetIntField(obj, gWebViewCoreFields.m_viewportHeight, s->viewportHeight()); 4778 env->SetIntField(obj, gWebViewCoreFields.m_viewportInitialScale, s->viewportInitialScale()); 4779 env->SetIntField(obj, gWebViewCoreFields.m_viewportMinimumScale, s->viewportMinimumScale()); 4780 env->SetIntField(obj, gWebViewCoreFields.m_viewportMaximumScale, s->viewportMaximumScale()); 4781 env->SetBooleanField(obj, gWebViewCoreFields.m_viewportUserScalable, s->viewportUserScalable()); 4782 env->SetIntField(obj, gWebViewCoreFields.m_viewportDensityDpi, s->viewportTargetDensityDpi()); 4783#endif 4784} 4785 4786static void SetBackgroundColor(JNIEnv* env, jobject obj, jint nativeClass, 4787 jint color) 4788{ 4789 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4790 ALOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); 4791 4792 viewImpl->setBackgroundColor((SkColor) color); 4793} 4794 4795static void DumpDomTree(JNIEnv* env, jobject obj, jint nativeClass, 4796 jboolean useFile) 4797{ 4798 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4799 ALOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); 4800 4801 viewImpl->dumpDomTree(useFile); 4802} 4803 4804static void DumpRenderTree(JNIEnv* env, jobject obj, jint nativeClass, 4805 jboolean useFile) 4806{ 4807 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4808 ALOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); 4809 4810 viewImpl->dumpRenderTree(useFile); 4811} 4812 4813static void SetJsFlags(JNIEnv* env, jobject obj, jint nativeClass, jstring flags) 4814{ 4815 WTF::String flagsString = jstringToWtfString(env, flags); 4816 WTF::CString utf8String = flagsString.utf8(); 4817 WebCore::ScriptController::setFlags(utf8String.data(), utf8String.length()); 4818} 4819 4820 4821// Called from the Java side to set a new quota for the origin or new appcache 4822// max size in response to a notification that the original quota was exceeded or 4823// that the appcache has reached its maximum size. 4824static void SetNewStorageLimit(JNIEnv* env, jobject obj, jint nativeClass, 4825 jlong quota) 4826{ 4827#if ENABLE(DATABASE) || ENABLE(OFFLINE_WEB_APPLICATIONS) 4828 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4829 Frame* frame = viewImpl->mainFrame(); 4830 4831 // The main thread is blocked awaiting this response, so now we can wake it 4832 // up. 4833 ChromeClientAndroid* chromeC = static_cast<ChromeClientAndroid*>(frame->page()->chrome()->client()); 4834 chromeC->wakeUpMainThreadWithNewQuota(quota); 4835#endif 4836} 4837 4838// Called from Java to provide a Geolocation permission state for the specified origin. 4839static void GeolocationPermissionsProvide(JNIEnv* env, jobject obj, 4840 jint nativeClass, jstring origin, jboolean allow, jboolean remember) 4841{ 4842 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4843 Frame* frame = viewImpl->mainFrame(); 4844 4845 ChromeClientAndroid* chromeClient = static_cast<ChromeClientAndroid*>(frame->page()->chrome()->client()); 4846 chromeClient->provideGeolocationPermissions(jstringToWtfString(env, origin), allow, remember); 4847} 4848 4849static void RegisterURLSchemeAsLocal(JNIEnv* env, jobject obj, jint nativeClass, 4850 jstring scheme) 4851{ 4852 WebCore::SchemeRegistry::registerURLSchemeAsLocal(jstringToWtfString(env, scheme)); 4853} 4854 4855static bool FocusBoundsChanged(JNIEnv* env, jobject obj, jint nativeClass) 4856{ 4857 return reinterpret_cast<WebViewCore*>(nativeClass)->focusBoundsChanged(); 4858} 4859 4860static void SetIsPaused(JNIEnv* env, jobject obj, jint nativeClass, 4861 jboolean isPaused) 4862{ 4863 // tell the webcore thread to stop thinking while we do other work 4864 // (selection and scrolling). This has nothing to do with the lifecycle 4865 // pause and resume. 4866 reinterpret_cast<WebViewCore*>(nativeClass)->setIsPaused(isPaused); 4867} 4868 4869static void Pause(JNIEnv* env, jobject obj, jint nativeClass) 4870{ 4871 // This is called for the foreground tab when the browser is put to the 4872 // background (and also for any tab when it is put to the background of the 4873 // browser). The browser can only be killed by the system when it is in the 4874 // background, so saving the Geolocation permission state now ensures that 4875 // is maintained when the browser is killed. 4876 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4877 ChromeClient* chromeClient = viewImpl->mainFrame()->page()->chrome()->client(); 4878 ChromeClientAndroid* chromeClientAndroid = static_cast<ChromeClientAndroid*>(chromeClient); 4879 chromeClientAndroid->storeGeolocationPermissions(); 4880 4881 Frame* mainFrame = viewImpl->mainFrame(); 4882 for (Frame* frame = mainFrame; frame; frame = frame->tree()->traverseNext()) { 4883 Geolocation* geolocation = frame->domWindow()->navigator()->optionalGeolocation(); 4884 if (geolocation) 4885 geolocation->suspend(); 4886 } 4887 4888 viewImpl->deviceMotionAndOrientationManager()->maybeSuspendClients(); 4889 4890 ANPEvent event; 4891 SkANP::InitEvent(&event, kLifecycle_ANPEventType); 4892 event.data.lifecycle.action = kPause_ANPLifecycleAction; 4893 viewImpl->sendPluginEvent(event); 4894 4895 viewImpl->setIsPaused(true); 4896} 4897 4898static void Resume(JNIEnv* env, jobject obj, jint nativeClass) 4899{ 4900 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4901 Frame* mainFrame = viewImpl->mainFrame(); 4902 for (Frame* frame = mainFrame; frame; frame = frame->tree()->traverseNext()) { 4903 Geolocation* geolocation = frame->domWindow()->navigator()->optionalGeolocation(); 4904 if (geolocation) 4905 geolocation->resume(); 4906 } 4907 4908 viewImpl->deviceMotionAndOrientationManager()->maybeResumeClients(); 4909 4910 ANPEvent event; 4911 SkANP::InitEvent(&event, kLifecycle_ANPEventType); 4912 event.data.lifecycle.action = kResume_ANPLifecycleAction; 4913 viewImpl->sendPluginEvent(event); 4914 4915 viewImpl->setIsPaused(false); 4916} 4917 4918static void FreeMemory(JNIEnv* env, jobject obj, jint nativeClass) 4919{ 4920 ANPEvent event; 4921 SkANP::InitEvent(&event, kLifecycle_ANPEventType); 4922 event.data.lifecycle.action = kFreeMemory_ANPLifecycleAction; 4923 reinterpret_cast<WebViewCore*>(nativeClass)->sendPluginEvent(event); 4924} 4925 4926static void ProvideVisitedHistory(JNIEnv* env, jobject obj, jint nativeClass, 4927 jobject hist) 4928{ 4929 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4930 ALOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); 4931 4932 jobjectArray array = static_cast<jobjectArray>(hist); 4933 4934 jsize len = env->GetArrayLength(array); 4935 for (jsize i = 0; i < len; i++) { 4936 jstring item = static_cast<jstring>(env->GetObjectArrayElement(array, i)); 4937 const UChar* str = static_cast<const UChar*>(env->GetStringChars(item, 0)); 4938 jsize len = env->GetStringLength(item); 4939 viewImpl->addVisitedLink(str, len); 4940 env->ReleaseStringChars(item, str); 4941 env->DeleteLocalRef(item); 4942 } 4943} 4944 4945static void PluginSurfaceReady(JNIEnv* env, jobject obj, jint nativeClass) 4946{ 4947 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4948 if (viewImpl) 4949 viewImpl->sendPluginSurfaceReady(); 4950} 4951 4952// Notification from the UI thread that the plugin's full-screen surface has been discarded 4953static void FullScreenPluginHidden(JNIEnv* env, jobject obj, jint nativeClass, 4954 jint npp) 4955{ 4956 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4957 PluginWidgetAndroid* plugin = viewImpl->getPluginWidget((NPP)npp); 4958 if (plugin) 4959 plugin->exitFullScreen(false); 4960} 4961 4962static WebCore::IntRect jrect_to_webrect(JNIEnv* env, jobject obj) 4963{ 4964 int L, T, R, B; 4965 GraphicsJNI::get_jrect(env, obj, &L, &T, &R, &B); 4966 return WebCore::IntRect(L, T, R - L, B - T); 4967} 4968 4969static jobject HitTest(JNIEnv* env, jobject obj, jint nativeClass, jint x, 4970 jint y, jint slop, jboolean doMoveMouse) 4971{ 4972 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4973 if (!viewImpl) 4974 return 0; 4975 AndroidHitTestResult result = viewImpl->hitTestAtPoint(x, y, slop, doMoveMouse); 4976 return result.createJavaObject(env); 4977} 4978 4979static void AutoFillForm(JNIEnv* env, jobject obj, jint nativeClass, 4980 jint queryId) 4981{ 4982#if ENABLE(WEB_AUTOFILL) 4983 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4984 if (!viewImpl) 4985 return; 4986 4987 WebCore::Frame* frame = viewImpl->mainFrame(); 4988 if (frame) { 4989 EditorClientAndroid* editorC = static_cast<EditorClientAndroid*>(frame->page()->editorClient()); 4990 WebAutofill* autoFill = editorC->getAutofill(); 4991 autoFill->fillFormFields(queryId); 4992 } 4993#endif 4994} 4995 4996static void CloseIdleConnections(JNIEnv* env, jobject obj, jint nativeClass) 4997{ 4998 WebCache::get(true)->closeIdleConnections(); 4999 WebCache::get(false)->closeIdleConnections(); 5000} 5001 5002static void nativeCertTrustChanged(JNIEnv *env, jobject obj) 5003{ 5004#if USE(CHROME_NETWORK_STACK) 5005 WebCache::get(true)->certTrustChanged(); 5006 WebCache::get(false)->certTrustChanged(); 5007#endif 5008} 5009 5010static void ScrollRenderLayer(JNIEnv* env, jobject obj, jint nativeClass, 5011 jint layer, jobject jRect) 5012{ 5013 SkRect rect; 5014 GraphicsJNI::jrect_to_rect(env, jRect, &rect); 5015 reinterpret_cast<WebViewCore*>(nativeClass)->scrollRenderLayer(layer, rect); 5016} 5017 5018static void DeleteText(JNIEnv* env, jobject obj, jint nativeClass, 5019 jint startX, jint startY, jint endX, jint endY) 5020{ 5021 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 5022 viewImpl->deleteText(startX, startY, endX, endY); 5023} 5024 5025static void InsertText(JNIEnv* env, jobject obj, jint nativeClass, 5026 jstring text) 5027{ 5028 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 5029 WTF::String wtfText = jstringToWtfString(env, text); 5030 viewImpl->insertText(wtfText); 5031} 5032 5033static jobject GetText(JNIEnv* env, jobject obj, jint nativeClass, 5034 jint startX, jint startY, jint endX, jint endY) 5035{ 5036 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 5037 WTF::String text = viewImpl->getText(startX, startY, endX, endY); 5038 return text.isEmpty() ? 0 : wtfStringToJstring(env, text); 5039} 5040 5041static void SelectText(JNIEnv* env, jobject obj, jint nativeClass, 5042 jint startX, jint startY, jint endX, jint endY) 5043{ 5044 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 5045 viewImpl->selectText(startX, startY, endX, endY); 5046} 5047 5048static void ClearSelection(JNIEnv* env, jobject obj, jint nativeClass) 5049{ 5050 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 5051 viewImpl->focusedFrame()->selection()->clear(); 5052} 5053 5054static bool SelectWordAt(JNIEnv* env, jobject obj, jint nativeClass, jint x, jint y) 5055{ 5056 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 5057 return viewImpl->selectWordAt(x, y); 5058} 5059 5060static void SelectAll(JNIEnv* env, jobject obj, jint nativeClass) 5061{ 5062 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 5063 viewImpl->focusedFrame()->selection()->selectAll(); 5064} 5065 5066static int FindAll(JNIEnv* env, jobject obj, jint nativeClass, 5067 jstring text) 5068{ 5069 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 5070 WTF::String wtfText = jstringToWtfString(env, text); 5071 return viewImpl->findTextOnPage(wtfText); 5072} 5073 5074static int FindNext(JNIEnv* env, jobject obj, jint nativeClass, 5075 jboolean forward) 5076{ 5077 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 5078 return viewImpl->findNextOnPage(forward); 5079} 5080 5081// ---------------------------------------------------------------------------- 5082 5083/* 5084 * JNI registration. 5085 */ 5086static JNINativeMethod gJavaWebViewCoreMethods[] = { 5087 { "nativeClearContent", "(I)V", 5088 (void*) ClearContent }, 5089 { "nativeFocusBoundsChanged", "(I)Z", 5090 (void*) FocusBoundsChanged } , 5091 { "nativeKey", "(IIIIZZZZ)Z", 5092 (void*) Key }, 5093 { "nativeClick", "(IIIZ)V", 5094 (void*) Click }, 5095 { "nativeContentInvalidateAll", "(I)V", 5096 (void*) ContentInvalidateAll }, 5097 { "nativeSendListBoxChoices", "(I[ZI)V", 5098 (void*) SendListBoxChoices }, 5099 { "nativeSendListBoxChoice", "(II)V", 5100 (void*) SendListBoxChoice }, 5101 { "nativeSetSize", "(IIIIFIIIIZ)V", 5102 (void*) SetSize }, 5103 { "nativeSetScrollOffset", "(IZII)V", 5104 (void*) SetScrollOffset }, 5105 { "nativeSetGlobalBounds", "(IIIII)V", 5106 (void*) SetGlobalBounds }, 5107 { "nativeSetSelection", "(III)V", 5108 (void*) SetSelection } , 5109 { "nativeModifySelection", "(III)Ljava/lang/String;", 5110 (void*) ModifySelection }, 5111 { "nativeDeleteSelection", "(IIII)V", 5112 (void*) DeleteSelection } , 5113 { "nativeReplaceTextfieldText", "(IIILjava/lang/String;III)V", 5114 (void*) ReplaceTextfieldText } , 5115 { "nativeMoveMouse", "(III)V", 5116 (void*) MoveMouse }, 5117 { "passToJs", "(IILjava/lang/String;IIZZZZ)V", 5118 (void*) PassToJs }, 5119 { "nativeScrollFocusedTextInput", "(IFI)V", 5120 (void*) ScrollFocusedTextInput }, 5121 { "nativeSetFocusControllerActive", "(IZ)V", 5122 (void*) SetFocusControllerActive }, 5123 { "nativeSaveDocumentState", "(I)V", 5124 (void*) SaveDocumentState }, 5125 { "nativeFindAddress", "(Ljava/lang/String;Z)Ljava/lang/String;", 5126 (void*) FindAddress }, 5127 { "nativeHandleTouchEvent", "(II[I[I[IIII)Z", 5128 (void*) HandleTouchEvent }, 5129 { "nativeTouchUp", "(IIIIII)V", 5130 (void*) TouchUp }, 5131 { "nativeMouseClick", "(I)Z", 5132 (void*) MouseClick }, 5133 { "nativeRetrieveHref", "(III)Ljava/lang/String;", 5134 (void*) RetrieveHref }, 5135 { "nativeRetrieveAnchorText", "(III)Ljava/lang/String;", 5136 (void*) RetrieveAnchorText }, 5137 { "nativeRetrieveImageSource", "(III)Ljava/lang/String;", 5138 (void*) RetrieveImageSource }, 5139 { "nativeGetContentMinPrefWidth", "(I)I", 5140 (void*) GetContentMinPrefWidth }, 5141 { "nativeUpdateLayers", "(II)Z", 5142 (void*) UpdateLayers }, 5143 { "nativeNotifyAnimationStarted", "(I)V", 5144 (void*) NotifyAnimationStarted }, 5145 { "nativeRecordContent", "(ILandroid/graphics/Region;Landroid/graphics/Point;)I", 5146 (void*) RecordContent }, 5147 { "setViewportSettingsFromNative", "(I)V", 5148 (void*) SetViewportSettingsFromNative }, 5149 { "nativeSplitContent", "(II)V", 5150 (void*) SplitContent }, 5151 { "nativeSetBackgroundColor", "(II)V", 5152 (void*) SetBackgroundColor }, 5153 { "nativeRegisterURLSchemeAsLocal", "(ILjava/lang/String;)V", 5154 (void*) RegisterURLSchemeAsLocal }, 5155 { "nativeDumpDomTree", "(IZ)V", 5156 (void*) DumpDomTree }, 5157 { "nativeDumpRenderTree", "(IZ)V", 5158 (void*) DumpRenderTree }, 5159 { "nativeSetNewStorageLimit", "(IJ)V", 5160 (void*) SetNewStorageLimit }, 5161 { "nativeGeolocationPermissionsProvide", "(ILjava/lang/String;ZZ)V", 5162 (void*) GeolocationPermissionsProvide }, 5163 { "nativeSetIsPaused", "(IZ)V", (void*) SetIsPaused }, 5164 { "nativePause", "(I)V", (void*) Pause }, 5165 { "nativeResume", "(I)V", (void*) Resume }, 5166 { "nativeFreeMemory", "(I)V", (void*) FreeMemory }, 5167 { "nativeSetJsFlags", "(ILjava/lang/String;)V", (void*) SetJsFlags }, 5168 { "nativeRequestLabel", "(III)Ljava/lang/String;", 5169 (void*) RequestLabel }, 5170 { "nativeRevealSelection", "(I)V", (void*) RevealSelection }, 5171 { "nativeProvideVisitedHistory", "(I[Ljava/lang/String;)V", 5172 (void*) ProvideVisitedHistory }, 5173 { "nativeFullScreenPluginHidden", "(II)V", 5174 (void*) FullScreenPluginHidden }, 5175 { "nativePluginSurfaceReady", "(I)V", 5176 (void*) PluginSurfaceReady }, 5177 { "nativeHitTest", "(IIIIZ)Landroid/webkit/WebViewCore$WebKitHitTest;", 5178 (void*) HitTest }, 5179 { "nativeAutoFillForm", "(II)V", 5180 (void*) AutoFillForm }, 5181 { "nativeScrollLayer", "(IILandroid/graphics/Rect;)V", 5182 (void*) ScrollRenderLayer }, 5183 { "nativeCloseIdleConnections", "(I)V", 5184 (void*) CloseIdleConnections }, 5185 { "nativeDeleteText", "(IIIII)V", 5186 (void*) DeleteText }, 5187 { "nativeInsertText", "(ILjava/lang/String;)V", 5188 (void*) InsertText }, 5189 { "nativeGetText", "(IIIII)Ljava/lang/String;", 5190 (void*) GetText }, 5191 { "nativeSelectText", "(IIIII)V", 5192 (void*) SelectText }, 5193 { "nativeClearTextSelection", "(I)V", 5194 (void*) ClearSelection }, 5195 { "nativeSelectWordAt", "(III)Z", 5196 (void*) SelectWordAt }, 5197 { "nativeSelectAll", "(I)V", 5198 (void*) SelectAll }, 5199 { "nativeCertTrustChanged","()V", 5200 (void*) nativeCertTrustChanged }, 5201 { "nativeFindAll", "(ILjava/lang/String;)I", 5202 (void*) FindAll }, 5203 { "nativeFindNext", "(IZ)I", 5204 (void*) FindNext }, 5205}; 5206 5207int registerWebViewCore(JNIEnv* env) 5208{ 5209 jclass widget = env->FindClass("android/webkit/WebViewCore"); 5210 ALOG_ASSERT(widget, 5211 "Unable to find class android/webkit/WebViewCore"); 5212 gWebViewCoreFields.m_nativeClass = env->GetFieldID(widget, "mNativeClass", 5213 "I"); 5214 ALOG_ASSERT(gWebViewCoreFields.m_nativeClass, 5215 "Unable to find android/webkit/WebViewCore.mNativeClass"); 5216 gWebViewCoreFields.m_viewportWidth = env->GetFieldID(widget, 5217 "mViewportWidth", "I"); 5218 ALOG_ASSERT(gWebViewCoreFields.m_viewportWidth, 5219 "Unable to find android/webkit/WebViewCore.mViewportWidth"); 5220 gWebViewCoreFields.m_viewportHeight = env->GetFieldID(widget, 5221 "mViewportHeight", "I"); 5222 ALOG_ASSERT(gWebViewCoreFields.m_viewportHeight, 5223 "Unable to find android/webkit/WebViewCore.mViewportHeight"); 5224 gWebViewCoreFields.m_viewportInitialScale = env->GetFieldID(widget, 5225 "mViewportInitialScale", "I"); 5226 ALOG_ASSERT(gWebViewCoreFields.m_viewportInitialScale, 5227 "Unable to find android/webkit/WebViewCore.mViewportInitialScale"); 5228 gWebViewCoreFields.m_viewportMinimumScale = env->GetFieldID(widget, 5229 "mViewportMinimumScale", "I"); 5230 ALOG_ASSERT(gWebViewCoreFields.m_viewportMinimumScale, 5231 "Unable to find android/webkit/WebViewCore.mViewportMinimumScale"); 5232 gWebViewCoreFields.m_viewportMaximumScale = env->GetFieldID(widget, 5233 "mViewportMaximumScale", "I"); 5234 ALOG_ASSERT(gWebViewCoreFields.m_viewportMaximumScale, 5235 "Unable to find android/webkit/WebViewCore.mViewportMaximumScale"); 5236 gWebViewCoreFields.m_viewportUserScalable = env->GetFieldID(widget, 5237 "mViewportUserScalable", "Z"); 5238 ALOG_ASSERT(gWebViewCoreFields.m_viewportUserScalable, 5239 "Unable to find android/webkit/WebViewCore.mViewportUserScalable"); 5240 gWebViewCoreFields.m_viewportDensityDpi = env->GetFieldID(widget, 5241 "mViewportDensityDpi", "I"); 5242 ALOG_ASSERT(gWebViewCoreFields.m_viewportDensityDpi, 5243 "Unable to find android/webkit/WebViewCore.mViewportDensityDpi"); 5244 gWebViewCoreFields.m_drawIsPaused = env->GetFieldID(widget, 5245 "mDrawIsPaused", "Z"); 5246 ALOG_ASSERT(gWebViewCoreFields.m_drawIsPaused, 5247 "Unable to find android/webkit/WebViewCore.mDrawIsPaused"); 5248 gWebViewCoreFields.m_lowMemoryUsageMb = env->GetFieldID(widget, "mLowMemoryUsageThresholdMb", "I"); 5249 gWebViewCoreFields.m_highMemoryUsageMb = env->GetFieldID(widget, "mHighMemoryUsageThresholdMb", "I"); 5250 gWebViewCoreFields.m_highUsageDeltaMb = env->GetFieldID(widget, "mHighUsageDeltaMb", "I"); 5251 5252 gWebViewCoreStaticMethods.m_isSupportedMediaMimeType = 5253 env->GetStaticMethodID(widget, "isSupportedMediaMimeType", "(Ljava/lang/String;)Z"); 5254 LOG_FATAL_IF(!gWebViewCoreStaticMethods.m_isSupportedMediaMimeType, 5255 "Could not find static method isSupportedMediaMimeType from WebViewCore"); 5256 5257 env->DeleteLocalRef(widget); 5258 5259 return jniRegisterNativeMethods(env, "android/webkit/WebViewCore", 5260 gJavaWebViewCoreMethods, NELEM(gJavaWebViewCoreMethods)); 5261} 5262 5263} /* namespace android */ 5264