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