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