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