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