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