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