WebViewCore.cpp revision 8266295cc837f73c2bcfbcca3f8b330d4991fc0e
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 3267bool WebViewCore::performMouseClick() 3268{ 3269 WebCore::PlatformMouseEvent mouseDown(m_mousePos, m_mousePos, WebCore::LeftButton, 3270 WebCore::MouseEventPressed, 1, false, false, false, false, 3271 WTF::currentTime()); 3272 // ignore the return from as it will return true if the hit point can trigger selection change 3273 m_mainFrame->eventHandler()->handleMousePressEvent(mouseDown); 3274 WebCore::PlatformMouseEvent mouseUp(m_mousePos, m_mousePos, WebCore::LeftButton, 3275 WebCore::MouseEventReleased, 1, false, false, false, false, 3276 WTF::currentTime()); 3277 bool handled = m_mainFrame->eventHandler()->handleMouseReleaseEvent(mouseUp); 3278 3279 WebCore::Node* focusNode = currentFocus(); 3280 initializeTextInput(focusNode, false); 3281 return handled; 3282} 3283 3284// Check for the "x-webkit-soft-keyboard" attribute. If it is there and 3285// set to hidden, do not show the soft keyboard. Node passed as a parameter 3286// must not be null. 3287static bool shouldSuppressKeyboard(const WebCore::Node* node) { 3288 ALOG_ASSERT(node, "node passed to shouldSuppressKeyboard cannot be null"); 3289 const NamedNodeMap* attributes = node->attributes(); 3290 if (!attributes) return false; 3291 size_t length = attributes->length(); 3292 for (size_t i = 0; i < length; i++) { 3293 const Attribute* a = attributes->attributeItem(i); 3294 if (a->localName() == "x-webkit-soft-keyboard" && a->value() == "hidden") 3295 return true; 3296 } 3297 return false; 3298} 3299 3300// Common code for both clicking with the trackball and touchUp 3301// Also used when typing into a non-focused textfield to give the textfield focus, 3302// in which case, 'fake' is set to true 3303bool WebViewCore::handleMouseClick(WebCore::Frame* framePtr, WebCore::Node* nodePtr, bool fake) 3304{ 3305 bool valid = !framePtr || validNode(m_mainFrame, framePtr, nodePtr); 3306 WebFrame* webFrame = WebFrame::getWebFrame(m_mainFrame); 3307 if (valid && nodePtr) { 3308 // Need to special case area tags because an image map could have an area element in the middle 3309 // so when attempting to get the default, the point chosen would be follow the wrong link. 3310 if (nodePtr->hasTagName(WebCore::HTMLNames::areaTag)) { 3311 nodePtr->dispatchSimulatedClick(0, true, true); 3312 return true; 3313 } 3314 } 3315 if (!valid || !framePtr) 3316 framePtr = m_mainFrame; 3317 WebCore::PlatformMouseEvent mouseDown(m_mousePos, m_mousePos, WebCore::LeftButton, 3318 WebCore::MouseEventPressed, 1, false, false, false, false, 3319 WTF::currentTime()); 3320 // ignore the return from as it will return true if the hit point can trigger selection change 3321 framePtr->eventHandler()->handleMousePressEvent(mouseDown); 3322 WebCore::PlatformMouseEvent mouseUp(m_mousePos, m_mousePos, WebCore::LeftButton, 3323 WebCore::MouseEventReleased, 1, false, false, false, false, 3324 WTF::currentTime()); 3325 bool handled = framePtr->eventHandler()->handleMouseReleaseEvent(mouseUp); 3326 3327 WebCore::Node* focusNode = currentFocus(); 3328 initializeTextInput(focusNode, fake); 3329 return handled; 3330} 3331 3332WebViewCore::InputType WebViewCore::getInputType(Node* node) 3333{ 3334 WebCore::RenderObject* renderer = node->renderer(); 3335 if (!renderer) 3336 return WebViewCore::NONE; 3337 if (renderer->isTextArea()) 3338 return WebViewCore::TEXT_AREA; 3339 3340 if (node->hasTagName(WebCore::HTMLNames::inputTag)) { 3341 HTMLInputElement* htmlInput = static_cast<HTMLInputElement*>(node); 3342 if (htmlInput->isPasswordField()) 3343 return WebViewCore::PASSWORD; 3344 if (htmlInput->isSearchField()) 3345 return WebViewCore::SEARCH; 3346 if (htmlInput->isEmailField()) 3347 return WebViewCore::EMAIL; 3348 if (htmlInput->isNumberField()) 3349 return WebViewCore::NUMBER; 3350 if (htmlInput->isTelephoneField()) 3351 return WebViewCore::TELEPHONE; 3352 if (htmlInput->isTextField()) 3353 return WebViewCore::NORMAL_TEXT_FIELD; 3354 } 3355 3356 if (node->isContentEditable()) 3357 return WebViewCore::TEXT_AREA; 3358 3359 return WebViewCore::NONE; 3360} 3361 3362int WebViewCore::getMaxLength(Node* node) 3363{ 3364 int maxLength = -1; 3365 if (node->hasTagName(WebCore::HTMLNames::inputTag)) { 3366 HTMLInputElement* htmlInput = static_cast<HTMLInputElement*>(node); 3367 maxLength = htmlInput->maxLength(); 3368 } 3369 return maxLength; 3370} 3371 3372String WebViewCore::getFieldName(Node* node) 3373{ 3374 String name; 3375 if (node->hasTagName(WebCore::HTMLNames::inputTag)) { 3376 HTMLInputElement* htmlInput = static_cast<HTMLInputElement*>(node); 3377 name = htmlInput->name(); 3378 } 3379 return name; 3380} 3381 3382bool WebViewCore::isSpellCheckEnabled(Node* node) 3383{ 3384 bool isEnabled = true; 3385 if (node->isElementNode()) { 3386 WebCore::Element* element = static_cast<WebCore::Element*>(node); 3387 isEnabled = element->isSpellCheckingEnabled(); 3388 } 3389 return isEnabled; 3390} 3391 3392bool WebViewCore::isAutoCompleteEnabled(Node* node) 3393{ 3394 bool isEnabled = false; 3395 if (node->hasTagName(WebCore::HTMLNames::inputTag)) { 3396 HTMLInputElement* htmlInput = static_cast<HTMLInputElement*>(node); 3397 isEnabled = htmlInput->autoComplete(); 3398 } 3399 return isEnabled; 3400} 3401 3402WebCore::IntRect WebViewCore::absoluteContentRect(WebCore::Node* node, 3403 LayerAndroid* layer) 3404{ 3405 IntRect contentRect; 3406 if (node) { 3407 RenderObject* render = node->renderer(); 3408 if (render && render->isBox() && !render->isBody()) { 3409 IntPoint offset = convertGlobalContentToFrameContent(IntPoint(), 3410 node->document()->frame()); 3411 WebViewCore::layerToAbsoluteOffset(layer, offset); 3412 3413 RenderBox* renderBox = toRenderBox(render); 3414 contentRect = renderBox->absoluteContentBox(); 3415 contentRect.move(-offset.x(), -offset.y()); 3416 } 3417 } 3418 return contentRect; 3419} 3420 3421jobject WebViewCore::createTextFieldInitData(Node* node) 3422{ 3423 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3424 TextFieldInitDataGlue* classDef = m_textFieldInitDataGlue; 3425 jclass clazz = env->FindClass("android/webkit/WebViewCore$TextFieldInitData"); 3426 jobject initData = env->NewObject(clazz, classDef->m_constructor); 3427 env->SetIntField(initData, classDef->m_fieldPointer, 3428 reinterpret_cast<int>(node)); 3429 env->SetObjectField(initData, classDef->m_text, 3430 wtfStringToJstring(env, getInputText(node), true)); 3431 env->SetIntField(initData, classDef->m_type, getInputType(node)); 3432 env->SetBooleanField(initData, classDef->m_isSpellCheckEnabled, 3433 isSpellCheckEnabled(node)); 3434 Document* document = node->document(); 3435 PlatformKeyboardEvent tab(AKEYCODE_TAB, 0, 0, false, false, false, false); 3436 PassRefPtr<KeyboardEvent> tabEvent = 3437 KeyboardEvent::create(tab, document->defaultView()); 3438 env->SetBooleanField(initData, classDef->m_isTextFieldNext, 3439 isTextInput(document->nextFocusableNode(node, tabEvent.get()))); 3440 env->SetBooleanField(initData, classDef->m_isTextFieldPrev, 3441 isTextInput(document->previousFocusableNode(node, tabEvent.get()))); 3442 env->SetBooleanField(initData, classDef->m_isAutoCompleteEnabled, 3443 isAutoCompleteEnabled(node)); 3444 env->SetObjectField(initData, classDef->m_name, 3445 wtfStringToJstring(env, getFieldName(node), false)); 3446 env->SetObjectField(initData, classDef->m_name, 3447 wtfStringToJstring(env, requestLabel(document->frame(), node), false)); 3448 env->SetIntField(initData, classDef->m_maxLength, getMaxLength(node)); 3449 LayerAndroid* layer = 0; 3450 int layerId = platformLayerIdFromNode(node, &layer); 3451 IntRect bounds = absoluteContentRect(node, layer); 3452 env->SetObjectField(initData, classDef->m_contentBounds, 3453 intRectToRect(env, bounds)); 3454 env->SetIntField(initData, classDef->m_nodeLayerId, layerId); 3455 IntRect contentRect; 3456 RenderTextControl* rtc = toRenderTextControl(node); 3457 if (rtc) { 3458 contentRect.setWidth(rtc->scrollWidth()); 3459 contentRect.setHeight(rtc->scrollHeight()); 3460 contentRect.move(-rtc->scrollLeft(), -rtc->scrollTop()); 3461 } 3462 env->SetObjectField(initData, classDef->m_contentRect, 3463 intRectToRect(env, contentRect)); 3464 return initData; 3465} 3466 3467void WebViewCore::initEditField(Node* node) 3468{ 3469 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3470 AutoJObject javaObject = m_javaGlue->object(env); 3471 if (!javaObject.get()) 3472 return; 3473 m_textGeneration = 0; 3474 int start = 0; 3475 int end = 0; 3476 getSelectionOffsets(node, start, end); 3477 SelectText* selectText = createSelectText(focusedFrame()->selection()->selection()); 3478 env->CallVoidMethod(javaObject.get(), m_javaGlue->m_initEditField, 3479 start, end, reinterpret_cast<int>(selectText), 3480 createTextFieldInitData(node)); 3481 checkException(env); 3482} 3483 3484void WebViewCore::popupReply(int index) 3485{ 3486 if (m_popupReply) { 3487 m_popupReply->replyInt(index); 3488 Release(m_popupReply); 3489 m_popupReply = 0; 3490 } 3491} 3492 3493void WebViewCore::popupReply(const int* array, int count) 3494{ 3495 if (m_popupReply) { 3496 m_popupReply->replyIntArray(array, count); 3497 Release(m_popupReply); 3498 m_popupReply = 0; 3499 } 3500} 3501 3502// This is a slightly modified Node::nextNodeConsideringAtomicNodes() with the 3503// extra constraint of limiting the search to inside a containing parent 3504WebCore::Node* nextNodeWithinParent(WebCore::Node* parent, WebCore::Node* start) 3505{ 3506 if (!isAtomicNode(start) && start->firstChild()) 3507 return start->firstChild(); 3508 if (start->nextSibling()) 3509 return start->nextSibling(); 3510 const Node *n = start; 3511 while (n && !n->nextSibling()) { 3512 n = n->parentNode(); 3513 if (n == parent) 3514 return 0; 3515 } 3516 if (n) 3517 return n->nextSibling(); 3518 return 0; 3519} 3520 3521void WebViewCore::initializeTextInput(WebCore::Node* node, bool fake) 3522{ 3523 if (node) { 3524 if (isTextInput(node)) { 3525 bool showKeyboard = true; 3526 initEditField(node); 3527 WebCore::RenderTextControl* rtc = toRenderTextControl(node); 3528 if (rtc && node->hasTagName(HTMLNames::inputTag)) { 3529 HTMLInputElement* inputElement = static_cast<HTMLInputElement*>(node); 3530 bool ime = !shouldSuppressKeyboard(node) && !inputElement->readOnly(); 3531 if (ime) { 3532#if ENABLE(WEB_AUTOFILL) 3533 if (rtc->isTextField()) { 3534 Page* page = node->document()->page(); 3535 EditorClient* editorClient = page->editorClient(); 3536 EditorClientAndroid* androidEditor = 3537 static_cast<EditorClientAndroid*>(editorClient); 3538 WebAutofill* autoFill = androidEditor->getAutofill(); 3539 autoFill->formFieldFocused(inputElement); 3540 } 3541#endif 3542 } else 3543 showKeyboard = false; 3544 } 3545 if (!fake) 3546 requestKeyboard(showKeyboard); 3547 } else if (!fake && !nodeIsPlugin(node)) { 3548 // not a text entry field, put away the keyboard. 3549 clearTextEntry(); 3550 } 3551 } else if (!fake) { 3552 // There is no focusNode, so the keyboard is not needed. 3553 clearTextEntry(); 3554 } 3555} 3556 3557void WebViewCore::focusNodeChanged(WebCore::Node* newFocus) 3558{ 3559 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3560 AutoJObject javaObject = m_javaGlue->object(env); 3561 if (!javaObject.get()) 3562 return; 3563 if (isTextInput(newFocus)) 3564 initializeTextInput(newFocus, true); 3565 HitTestResult focusHitResult; 3566 focusHitResult.setInnerNode(newFocus); 3567 focusHitResult.setInnerNonSharedNode(newFocus); 3568 if (newFocus && newFocus->isLink() && newFocus->isElementNode()) { 3569 focusHitResult.setURLElement(static_cast<Element*>(newFocus)); 3570 if (newFocus->hasChildNodes() && !newFocus->hasTagName(HTMLNames::imgTag)) { 3571 // Check to see if any of the children are images, and if so 3572 // set them as the innerNode and innerNonSharedNode 3573 // This will stop when it hits the first image. I'm not sure what 3574 // should be done in the case of multiple images inside one anchor... 3575 Node* nextNode = newFocus->firstChild(); 3576 bool found = false; 3577 while (nextNode) { 3578 if (nextNode->hasTagName(HTMLNames::imgTag)) { 3579 found = true; 3580 break; 3581 } 3582 nextNode = nextNodeWithinParent(newFocus, nextNode); 3583 } 3584 if (found) { 3585 focusHitResult.setInnerNode(nextNode); 3586 focusHitResult.setInnerNonSharedNode(nextNode); 3587 } 3588 } 3589 } 3590 AndroidHitTestResult androidHitTest(this, focusHitResult); 3591 jobject jHitTestObj = androidHitTest.createJavaObject(env); 3592 env->CallVoidMethod(javaObject.get(), m_javaGlue->m_focusNodeChanged, 3593 reinterpret_cast<int>(newFocus), jHitTestObj); 3594 env->DeleteLocalRef(jHitTestObj); 3595} 3596 3597void WebViewCore::addMessageToConsole(const WTF::String& message, unsigned int lineNumber, const WTF::String& sourceID, int msgLevel) { 3598 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3599 AutoJObject javaObject = m_javaGlue->object(env); 3600 if (!javaObject.get()) 3601 return; 3602 jstring jMessageStr = wtfStringToJstring(env, message); 3603 jstring jSourceIDStr = wtfStringToJstring(env, sourceID); 3604 env->CallVoidMethod(javaObject.get(), 3605 m_javaGlue->m_addMessageToConsole, jMessageStr, lineNumber, 3606 jSourceIDStr, msgLevel); 3607 env->DeleteLocalRef(jMessageStr); 3608 env->DeleteLocalRef(jSourceIDStr); 3609 checkException(env); 3610} 3611 3612void WebViewCore::jsAlert(const WTF::String& url, const WTF::String& text) 3613{ 3614 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3615 AutoJObject javaObject = m_javaGlue->object(env); 3616 if (!javaObject.get()) 3617 return; 3618 jstring jInputStr = wtfStringToJstring(env, text); 3619 jstring jUrlStr = wtfStringToJstring(env, url); 3620 env->CallVoidMethod(javaObject.get(), m_javaGlue->m_jsAlert, jUrlStr, jInputStr); 3621 env->DeleteLocalRef(jInputStr); 3622 env->DeleteLocalRef(jUrlStr); 3623 checkException(env); 3624} 3625 3626bool WebViewCore::exceededDatabaseQuota(const WTF::String& url, const WTF::String& databaseIdentifier, const unsigned long long currentQuota, unsigned long long estimatedSize) 3627{ 3628#if ENABLE(DATABASE) 3629 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3630 AutoJObject javaObject = m_javaGlue->object(env); 3631 if (!javaObject.get()) 3632 return false; 3633 jstring jDatabaseIdentifierStr = wtfStringToJstring(env, databaseIdentifier); 3634 jstring jUrlStr = wtfStringToJstring(env, url); 3635 env->CallVoidMethod(javaObject.get(), 3636 m_javaGlue->m_exceededDatabaseQuota, jUrlStr, 3637 jDatabaseIdentifierStr, currentQuota, estimatedSize); 3638 env->DeleteLocalRef(jDatabaseIdentifierStr); 3639 env->DeleteLocalRef(jUrlStr); 3640 checkException(env); 3641 return true; 3642#endif 3643} 3644 3645bool WebViewCore::reachedMaxAppCacheSize(const unsigned long long spaceNeeded) 3646{ 3647#if ENABLE(OFFLINE_WEB_APPLICATIONS) 3648 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3649 AutoJObject javaObject = m_javaGlue->object(env); 3650 if (!javaObject.get()) 3651 return false; 3652 env->CallVoidMethod(javaObject.get(), m_javaGlue->m_reachedMaxAppCacheSize, spaceNeeded); 3653 checkException(env); 3654 return true; 3655#endif 3656} 3657 3658void WebViewCore::populateVisitedLinks(WebCore::PageGroup* group) 3659{ 3660 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3661 AutoJObject javaObject = m_javaGlue->object(env); 3662 if (!javaObject.get()) 3663 return; 3664 m_groupForVisitedLinks = group; 3665 env->CallVoidMethod(javaObject.get(), m_javaGlue->m_populateVisitedLinks); 3666 checkException(env); 3667} 3668 3669void WebViewCore::geolocationPermissionsShowPrompt(const WTF::String& origin) 3670{ 3671 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3672 AutoJObject javaObject = m_javaGlue->object(env); 3673 if (!javaObject.get()) 3674 return; 3675 jstring originString = wtfStringToJstring(env, origin); 3676 env->CallVoidMethod(javaObject.get(), 3677 m_javaGlue->m_geolocationPermissionsShowPrompt, 3678 originString); 3679 env->DeleteLocalRef(originString); 3680 checkException(env); 3681} 3682 3683void WebViewCore::geolocationPermissionsHidePrompt() 3684{ 3685 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3686 AutoJObject javaObject = m_javaGlue->object(env); 3687 if (!javaObject.get()) 3688 return; 3689 env->CallVoidMethod(javaObject.get(), m_javaGlue->m_geolocationPermissionsHidePrompt); 3690 checkException(env); 3691} 3692 3693jobject WebViewCore::getDeviceMotionService() 3694{ 3695 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3696 AutoJObject javaObject = m_javaGlue->object(env); 3697 if (!javaObject.get()) 3698 return 0; 3699 jobject object = env->CallObjectMethod(javaObject.get(), m_javaGlue->m_getDeviceMotionService); 3700 checkException(env); 3701 return object; 3702} 3703 3704jobject WebViewCore::getDeviceOrientationService() 3705{ 3706 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3707 AutoJObject javaObject = m_javaGlue->object(env); 3708 if (!javaObject.get()) 3709 return 0; 3710 jobject object = env->CallObjectMethod(javaObject.get(), m_javaGlue->m_getDeviceOrientationService); 3711 checkException(env); 3712 return object; 3713} 3714 3715bool WebViewCore::jsConfirm(const WTF::String& url, const WTF::String& text) 3716{ 3717 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3718 AutoJObject javaObject = m_javaGlue->object(env); 3719 if (!javaObject.get()) 3720 return false; 3721 jstring jInputStr = wtfStringToJstring(env, text); 3722 jstring jUrlStr = wtfStringToJstring(env, url); 3723 jboolean result = env->CallBooleanMethod(javaObject.get(), m_javaGlue->m_jsConfirm, jUrlStr, jInputStr); 3724 env->DeleteLocalRef(jInputStr); 3725 env->DeleteLocalRef(jUrlStr); 3726 checkException(env); 3727 return result; 3728} 3729 3730bool WebViewCore::jsPrompt(const WTF::String& url, const WTF::String& text, const WTF::String& defaultValue, WTF::String& result) 3731{ 3732 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3733 AutoJObject javaObject = m_javaGlue->object(env); 3734 if (!javaObject.get()) 3735 return false; 3736 jstring jUrlStr = wtfStringToJstring(env, url); 3737 jstring jInputStr = wtfStringToJstring(env, text); 3738 jstring jDefaultStr = wtfStringToJstring(env, defaultValue); 3739 jstring returnVal = static_cast<jstring>(env->CallObjectMethod(javaObject.get(), m_javaGlue->m_jsPrompt, jUrlStr, jInputStr, jDefaultStr)); 3740 env->DeleteLocalRef(jUrlStr); 3741 env->DeleteLocalRef(jInputStr); 3742 env->DeleteLocalRef(jDefaultStr); 3743 checkException(env); 3744 3745 // If returnVal is null, it means that the user cancelled the dialog. 3746 if (!returnVal) 3747 return false; 3748 3749 result = jstringToWtfString(env, returnVal); 3750 env->DeleteLocalRef(returnVal); 3751 return true; 3752} 3753 3754bool WebViewCore::jsUnload(const WTF::String& url, const WTF::String& message) 3755{ 3756 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3757 AutoJObject javaObject = m_javaGlue->object(env); 3758 if (!javaObject.get()) 3759 return false; 3760 jstring jInputStr = wtfStringToJstring(env, message); 3761 jstring jUrlStr = wtfStringToJstring(env, url); 3762 jboolean result = env->CallBooleanMethod(javaObject.get(), m_javaGlue->m_jsUnload, jUrlStr, jInputStr); 3763 env->DeleteLocalRef(jInputStr); 3764 env->DeleteLocalRef(jUrlStr); 3765 checkException(env); 3766 return result; 3767} 3768 3769bool WebViewCore::jsInterrupt() 3770{ 3771 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3772 AutoJObject javaObject = m_javaGlue->object(env); 3773 if (!javaObject.get()) 3774 return false; 3775 jboolean result = env->CallBooleanMethod(javaObject.get(), m_javaGlue->m_jsInterrupt); 3776 checkException(env); 3777 return result; 3778} 3779 3780AutoJObject 3781WebViewCore::getJavaObject() 3782{ 3783 return m_javaGlue->object(JSC::Bindings::getJNIEnv()); 3784} 3785 3786jobject 3787WebViewCore::getWebViewJavaObject() 3788{ 3789 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3790 AutoJObject javaObject = m_javaGlue->object(env); 3791 if (!javaObject.get()) 3792 return 0; 3793 return env->CallObjectMethod(javaObject.get(), m_javaGlue->m_getWebView); 3794} 3795 3796RenderTextControl* WebViewCore::toRenderTextControl(Node* node) 3797{ 3798 RenderTextControl* rtc = 0; 3799 RenderObject* renderer = node->renderer(); 3800 if (renderer && renderer->isTextControl()) { 3801 rtc = WebCore::toRenderTextControl(renderer); 3802 } 3803 return rtc; 3804} 3805 3806void WebViewCore::getSelectionOffsets(Node* node, int& start, int& end) 3807{ 3808 RenderTextControl* rtc = toRenderTextControl(node); 3809 if (rtc) { 3810 start = rtc->selectionStart(); 3811 end = rtc->selectionEnd(); 3812 } else { 3813 // It must be content editable field. 3814 Document* document = node->document(); 3815 Frame* frame = document->frame(); 3816 SelectionController* selector = frame->selection(); 3817 Position selectionStart = selector->start(); 3818 Position selectionEnd = selector->end(); 3819 Position startOfNode = firstPositionInNode(node); 3820 RefPtr<Range> startRange = Range::create(document, startOfNode, 3821 selectionStart); 3822 start = TextIterator::rangeLength(startRange.get(), true); 3823 RefPtr<Range> endRange = Range::create(document, startOfNode, 3824 selectionEnd); 3825 end = TextIterator::rangeLength(endRange.get(), true); 3826 } 3827} 3828 3829String WebViewCore::getInputText(Node* node) 3830{ 3831 String text; 3832 WebCore::RenderTextControl* renderText = toRenderTextControl(node); 3833 if (renderText) 3834 text = renderText->text(); 3835 else { 3836 // It must be content editable field. 3837 Position start = firstPositionInNode(node); 3838 Position end = lastPositionInNode(node); 3839 VisibleSelection allEditableText(start, end); 3840 if (allEditableText.isRange()) 3841 text = allEditableText.firstRange()->text(); 3842 } 3843 return text; 3844} 3845 3846void WebViewCore::updateTextSelection() 3847{ 3848 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3849 AutoJObject javaObject = m_javaGlue->object(env); 3850 if (!javaObject.get()) 3851 return; 3852 VisibleSelection selection = focusedFrame()->selection()->selection(); 3853 int start = 0; 3854 int end = 0; 3855 if (selection.isCaretOrRange()) 3856 getSelectionOffsets(selection.start().anchorNode(), start, end); 3857 SelectText* selectText = createSelectText(selection); 3858 env->CallVoidMethod(javaObject.get(), 3859 m_javaGlue->m_updateTextSelection, reinterpret_cast<int>(currentFocus()), 3860 start, end, m_textGeneration, reinterpret_cast<int>(selectText)); 3861 checkException(env); 3862} 3863 3864void WebViewCore::updateTextSizeAndScroll(WebCore::Node* node) 3865{ 3866 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3867 AutoJObject javaObject = m_javaGlue->object(env); 3868 if (!javaObject.get()) 3869 return; 3870 RenderTextControl* rtc = toRenderTextControl(node); 3871 if (!rtc) 3872 return; 3873 int width = rtc->scrollWidth(); 3874 int height = rtc->contentHeight(); 3875 int scrollX = rtc->scrollLeft(); 3876 int scrollY = rtc->scrollTop(); 3877 env->CallVoidMethod(javaObject.get(), m_javaGlue->m_updateTextSizeAndScroll, 3878 reinterpret_cast<int>(node), width, height, scrollX, scrollY); 3879 checkException(env); 3880} 3881 3882void WebViewCore::updateTextfield(WebCore::Node* ptr, bool changeToPassword, 3883 const WTF::String& text) 3884{ 3885 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3886 AutoJObject javaObject = m_javaGlue->object(env); 3887 if (!javaObject.get()) 3888 return; 3889 if (m_blockTextfieldUpdates) 3890 return; 3891 if (changeToPassword) { 3892 env->CallVoidMethod(javaObject.get(), m_javaGlue->m_updateTextfield, 3893 (int) ptr, true, 0, m_textGeneration); 3894 checkException(env); 3895 return; 3896 } 3897 jstring string = wtfStringToJstring(env, text); 3898 env->CallVoidMethod(javaObject.get(), m_javaGlue->m_updateTextfield, 3899 (int) ptr, false, string, m_textGeneration); 3900 env->DeleteLocalRef(string); 3901 checkException(env); 3902} 3903 3904void WebViewCore::clearTextEntry() 3905{ 3906 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3907 AutoJObject javaObject = m_javaGlue->object(env); 3908 if (!javaObject.get()) 3909 return; 3910 env->CallVoidMethod(javaObject.get(), m_javaGlue->m_clearTextEntry); 3911} 3912 3913void WebViewCore::setBackgroundColor(SkColor c) 3914{ 3915 WebCore::FrameView* view = m_mainFrame->view(); 3916 if (!view) 3917 return; 3918 3919 // need (int) cast to find the right constructor 3920 WebCore::Color bcolor((int)SkColorGetR(c), (int)SkColorGetG(c), 3921 (int)SkColorGetB(c), (int)SkColorGetA(c)); 3922 view->setBaseBackgroundColor(bcolor); 3923 3924 // Background color of 0 indicates we want a transparent background 3925 if (c == 0) 3926 view->setTransparent(true); 3927} 3928 3929jclass WebViewCore::getPluginClass(const WTF::String& libName, const char* className) 3930{ 3931 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3932 AutoJObject javaObject = m_javaGlue->object(env); 3933 if (!javaObject.get()) 3934 return 0; 3935 3936 jstring libString = wtfStringToJstring(env, libName); 3937 jstring classString = env->NewStringUTF(className); 3938 jobject pluginClass = env->CallObjectMethod(javaObject.get(), 3939 m_javaGlue->m_getPluginClass, 3940 libString, classString); 3941 checkException(env); 3942 3943 // cleanup unneeded local JNI references 3944 env->DeleteLocalRef(libString); 3945 env->DeleteLocalRef(classString); 3946 3947 if (pluginClass != 0) { 3948 return static_cast<jclass>(pluginClass); 3949 } else { 3950 return 0; 3951 } 3952} 3953 3954void WebViewCore::showFullScreenPlugin(jobject childView, int32_t orientation, NPP npp) 3955{ 3956 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3957 AutoJObject javaObject = m_javaGlue->object(env); 3958 if (!javaObject.get()) 3959 return; 3960 3961 env->CallVoidMethod(javaObject.get(), 3962 m_javaGlue->m_showFullScreenPlugin, 3963 childView, orientation, reinterpret_cast<int>(npp)); 3964 checkException(env); 3965} 3966 3967void WebViewCore::hideFullScreenPlugin() 3968{ 3969 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3970 AutoJObject javaObject = m_javaGlue->object(env); 3971 if (!javaObject.get()) 3972 return; 3973 env->CallVoidMethod(javaObject.get(), m_javaGlue->m_hideFullScreenPlugin); 3974 checkException(env); 3975} 3976 3977jobject WebViewCore::createSurface(jobject view) 3978{ 3979 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3980 AutoJObject javaObject = m_javaGlue->object(env); 3981 if (!javaObject.get()) 3982 return 0; 3983 jobject result = env->CallObjectMethod(javaObject.get(), m_javaGlue->m_createSurface, view); 3984 checkException(env); 3985 return result; 3986} 3987 3988jobject WebViewCore::addSurface(jobject view, 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 0; 3994 jobject result = env->CallObjectMethod(javaObject.get(), 3995 m_javaGlue->m_addSurface, 3996 view, x, y, width, height); 3997 checkException(env); 3998 return result; 3999} 4000 4001void WebViewCore::updateSurface(jobject childView, int x, int y, int width, int height) 4002{ 4003 JNIEnv* env = JSC::Bindings::getJNIEnv(); 4004 AutoJObject javaObject = m_javaGlue->object(env); 4005 if (!javaObject.get()) 4006 return; 4007 env->CallVoidMethod(javaObject.get(), 4008 m_javaGlue->m_updateSurface, childView, 4009 x, y, width, height); 4010 checkException(env); 4011} 4012 4013void WebViewCore::destroySurface(jobject childView) 4014{ 4015 JNIEnv* env = JSC::Bindings::getJNIEnv(); 4016 AutoJObject javaObject = m_javaGlue->object(env); 4017 if (!javaObject.get()) 4018 return; 4019 env->CallVoidMethod(javaObject.get(), m_javaGlue->m_destroySurface, childView); 4020 checkException(env); 4021} 4022 4023jobject WebViewCore::getContext() 4024{ 4025 JNIEnv* env = JSC::Bindings::getJNIEnv(); 4026 AutoJObject javaObject = m_javaGlue->object(env); 4027 if (!javaObject.get()) 4028 return 0; 4029 4030 jobject result = env->CallObjectMethod(javaObject.get(), m_javaGlue->m_getContext); 4031 checkException(env); 4032 return result; 4033} 4034 4035void WebViewCore::keepScreenOn(bool screenOn) { 4036 if ((screenOn && m_screenOnCounter == 0) || (!screenOn && m_screenOnCounter == 1)) { 4037 JNIEnv* env = JSC::Bindings::getJNIEnv(); 4038 AutoJObject javaObject = m_javaGlue->object(env); 4039 if (!javaObject.get()) 4040 return; 4041 env->CallVoidMethod(javaObject.get(), m_javaGlue->m_keepScreenOn, screenOn); 4042 checkException(env); 4043 } 4044 4045 // update the counter 4046 if (screenOn) 4047 m_screenOnCounter++; 4048 else if (m_screenOnCounter > 0) 4049 m_screenOnCounter--; 4050} 4051 4052void WebViewCore::showRect(int left, int top, int width, int height, 4053 int contentWidth, int contentHeight, float xPercentInDoc, 4054 float xPercentInView, float yPercentInDoc, float yPercentInView) 4055{ 4056 JNIEnv* env = JSC::Bindings::getJNIEnv(); 4057 AutoJObject javaObject = m_javaGlue->object(env); 4058 if (!javaObject.get()) 4059 return; 4060 env->CallVoidMethod(javaObject.get(), m_javaGlue->m_showRect, 4061 left, top, width, height, contentWidth, contentHeight, 4062 xPercentInDoc, xPercentInView, yPercentInDoc, yPercentInView); 4063 checkException(env); 4064} 4065 4066void WebViewCore::centerFitRect(int x, int y, int width, int height) 4067{ 4068 JNIEnv* env = JSC::Bindings::getJNIEnv(); 4069 AutoJObject javaObject = m_javaGlue->object(env); 4070 if (!javaObject.get()) 4071 return; 4072 env->CallVoidMethod(javaObject.get(), m_javaGlue->m_centerFitRect, x, y, width, height); 4073 checkException(env); 4074} 4075 4076void WebViewCore::setScrollbarModes(ScrollbarMode horizontalMode, ScrollbarMode verticalMode) 4077{ 4078 JNIEnv* env = JSC::Bindings::getJNIEnv(); 4079 AutoJObject javaObject = m_javaGlue->object(env); 4080 if (!javaObject.get()) 4081 return; 4082 env->CallVoidMethod(javaObject.get(), m_javaGlue->m_setScrollbarModes, horizontalMode, verticalMode); 4083 checkException(env); 4084} 4085 4086void WebViewCore::notifyWebAppCanBeInstalled() 4087{ 4088 JNIEnv* env = JSC::Bindings::getJNIEnv(); 4089 AutoJObject javaObject = m_javaGlue->object(env); 4090 if (!javaObject.get()) 4091 return; 4092 env->CallVoidMethod(javaObject.get(), m_javaGlue->m_setInstallableWebApp); 4093 checkException(env); 4094} 4095 4096#if ENABLE(VIDEO) 4097void WebViewCore::enterFullscreenForVideoLayer(int layerId, const WTF::String& url) 4098{ 4099 JNIEnv* env = JSC::Bindings::getJNIEnv(); 4100 AutoJObject javaObject = m_javaGlue->object(env); 4101 if (!javaObject.get()) 4102 return; 4103 jstring jUrlStr = wtfStringToJstring(env, url); 4104 env->CallVoidMethod(javaObject.get(), m_javaGlue->m_enterFullscreenForVideoLayer, layerId, jUrlStr); 4105 m_fullscreenVideoMode = true; 4106 checkException(env); 4107} 4108 4109void WebViewCore::exitFullscreenVideo() 4110{ 4111 JNIEnv* env = JSC::Bindings::getJNIEnv(); 4112 AutoJObject javaObject = m_javaGlue->object(env); 4113 if (!javaObject.get()) 4114 return; 4115 if (m_fullscreenVideoMode) { 4116 env->CallVoidMethod(javaObject.get(), m_javaGlue->m_exitFullscreenVideo); 4117 m_fullscreenVideoMode = false; 4118 } 4119 checkException(env); 4120} 4121#endif 4122 4123void WebViewCore::setWebTextViewAutoFillable(int queryId, const string16& previewSummary) 4124{ 4125#if ENABLE(WEB_AUTOFILL) 4126 JNIEnv* env = JSC::Bindings::getJNIEnv(); 4127 AutoJObject javaObject = m_javaGlue->object(env); 4128 if (!javaObject.get()) 4129 return; 4130 jstring preview = env->NewString(previewSummary.data(), previewSummary.length()); 4131 env->CallVoidMethod(javaObject.get(), m_javaGlue->m_setWebTextViewAutoFillable, queryId, preview); 4132 env->DeleteLocalRef(preview); 4133#endif 4134} 4135 4136bool WebViewCore::drawIsPaused() const 4137{ 4138 // returning true says scrollview should be offscreen, which pauses 4139 // gifs. because this is not again queried when we stop scrolling, we don't 4140 // use the stopping currently. 4141 return false; 4142} 4143 4144void WebViewCore::setWebRequestContextUserAgent() 4145{ 4146 // We cannot create a WebRequestContext, because we might not know it this is a private tab or not yet 4147 if (m_webRequestContext) 4148 m_webRequestContext->setUserAgent(WebFrame::getWebFrame(m_mainFrame)->userAgentForURL(0)); // URL not used 4149} 4150 4151void WebViewCore::setWebRequestContextCacheMode(int cacheMode) 4152{ 4153 m_cacheMode = cacheMode; 4154 // We cannot create a WebRequestContext, because we might not know it this is a private tab or not yet 4155 if (!m_webRequestContext) 4156 return; 4157 4158 m_webRequestContext->setCacheMode(cacheMode); 4159} 4160 4161WebRequestContext* WebViewCore::webRequestContext() 4162{ 4163 if (!m_webRequestContext) { 4164 Settings* settings = mainFrame()->settings(); 4165 m_webRequestContext = new WebRequestContext(settings && settings->privateBrowsingEnabled()); 4166 setWebRequestContextUserAgent(); 4167 setWebRequestContextCacheMode(m_cacheMode); 4168 } 4169 return m_webRequestContext.get(); 4170} 4171 4172void WebViewCore::scrollRenderLayer(int layer, const SkRect& rect) 4173{ 4174#if USE(ACCELERATED_COMPOSITING) 4175 GraphicsLayerAndroid* root = graphicsRootLayer(); 4176 if (!root) 4177 return; 4178 4179 LayerAndroid* layerAndroid = root->platformLayer(); 4180 if (!layerAndroid) 4181 return; 4182 4183 LayerAndroid* target = layerAndroid->findById(layer); 4184 if (!target) 4185 return; 4186 4187 RenderLayer* owner = target->owningLayer(); 4188 if (!owner) 4189 return; 4190 4191 if (owner->isRootLayer()) { 4192 FrameView* view = owner->renderer()->frame()->view(); 4193 IntPoint pt(rect.fLeft, rect.fTop); 4194 view->setScrollPosition(pt); 4195 } else 4196 owner->scrollToOffset(rect.fLeft, rect.fTop); 4197#endif 4198} 4199 4200Vector<VisibleSelection> WebViewCore::getTextRanges( 4201 int startX, int startY, int endX, int endY) 4202{ 4203 // These are the positions of the selection handles, 4204 // which reside below the line that they are selecting. 4205 // Use the vertical position higher, which will include 4206 // the selected text. 4207 startY--; 4208 endY--; 4209 VisiblePosition startSelect = visiblePositionForContentPoint(startX, startY); 4210 VisiblePosition endSelect = visiblePositionForContentPoint(endX, endY); 4211 Position start = startSelect.deepEquivalent(); 4212 Position end = endSelect.deepEquivalent(); 4213 Vector<VisibleSelection> ranges; 4214 if (!start.isNull() && !end.isNull()) { 4215 if (comparePositions(start, end) > 0) { 4216 swap(start, end); // RTL start/end positions may be swapped 4217 } 4218 Position nextRangeStart = start; 4219 Position previousRangeEnd; 4220 do { 4221 VisibleSelection selection(nextRangeStart, end); 4222 ranges.append(selection); 4223 previousRangeEnd = selection.end(); 4224 nextRangeStart = nextCandidate(previousRangeEnd); 4225 } while (comparePositions(previousRangeEnd, end) < 0); 4226 } 4227 return ranges; 4228} 4229 4230void WebViewCore::deleteText(int startX, int startY, int endX, int endY) 4231{ 4232 Vector<VisibleSelection> ranges = 4233 getTextRanges(startX, startY, endX, endY); 4234 4235 EditorClientAndroid* client = static_cast<EditorClientAndroid*>( 4236 m_mainFrame->editor()->client()); 4237 client->setUiGeneratedSelectionChange(true); 4238 4239 SelectionController* selector = m_mainFrame->selection(); 4240 for (size_t i = 0; i < ranges.size(); i++) { 4241 const VisibleSelection& selection = ranges[i]; 4242 if (selection.isContentEditable()) { 4243 selector->setSelection(selection, CharacterGranularity); 4244 Document* document = selection.start().anchorNode()->document(); 4245 WebCore::TypingCommand::deleteSelection(document, 0); 4246 } 4247 } 4248 client->setUiGeneratedSelectionChange(false); 4249} 4250 4251void WebViewCore::insertText(const WTF::String &text) 4252{ 4253 WebCore::Node* focus = currentFocus(); 4254 if (!focus || !isTextInput(focus)) 4255 return; 4256 4257 Document* document = focus->document(); 4258 4259 EditorClientAndroid* client = static_cast<EditorClientAndroid*>( 4260 m_mainFrame->editor()->client()); 4261 if (!client) 4262 return; 4263 client->setUiGeneratedSelectionChange(true); 4264 WebCore::TypingCommand::insertText(document, text, 4265 TypingCommand::PreventSpellChecking); 4266 client->setUiGeneratedSelectionChange(false); 4267} 4268 4269void WebViewCore::resetFindOnPage() 4270{ 4271 m_searchText.truncate(0); 4272 m_matchCount = 0; 4273 m_activeMatchIndex = 0; 4274 m_activeMatch = 0; 4275} 4276 4277int WebViewCore::findTextOnPage(const WTF::String &text) 4278{ 4279 resetFindOnPage(); // reset even if parameters are bad 4280 4281 WebCore::Frame* frame = m_mainFrame; 4282 if (!frame) 4283 return 0; 4284 4285 m_searchText = text; 4286 FindOptions findOptions = WebCore::CaseInsensitive; 4287 4288 do { 4289 frame->document()->markers()->removeMarkers(DocumentMarker::TextMatch); 4290 m_matchCount += frame->editor()->countMatchesForText(text, findOptions, 4291 0, true); 4292 frame->editor()->setMarkedTextMatchesAreHighlighted(true); 4293 frame = frame->tree()->traverseNextWithWrap(false); 4294 } while (frame); 4295 m_activeMatchIndex = m_matchCount - 1; // prime first findNext 4296 return m_matchCount; 4297} 4298 4299int WebViewCore::findNextOnPage(bool forward) 4300{ 4301 if (!m_mainFrame) 4302 return -1; 4303 if (!m_matchCount) 4304 return -1; 4305 4306 EditorClientAndroid* client = static_cast<EditorClientAndroid*>( 4307 m_mainFrame->editor()->client()); 4308 client->setUiGeneratedSelectionChange(true); 4309 4310 // Clear previous active match. 4311 if (m_activeMatch) { 4312 m_mainFrame->document()->markers()->setMarkersActive( 4313 m_activeMatch.get(), false); 4314 } 4315 4316 FindOptions findOptions = WebCore::CaseInsensitive 4317 | WebCore::StartInSelection | WebCore::WrapAround; 4318 if (!forward) 4319 findOptions |= WebCore::Backwards; 4320 4321 // Start from the previous active match. 4322 if (m_activeMatch) { 4323 m_mainFrame->selection()->setSelection(m_activeMatch.get()); 4324 } 4325 4326 bool found = m_mainFrame->editor()->findString(m_searchText, findOptions); 4327 if (found) { 4328 VisibleSelection selection(m_mainFrame->selection()->selection()); 4329 if (selection.isNone() || selection.start() == selection.end()) { 4330 // Temporary workaround for findString() refusing to select text 4331 // marked "-webkit-user-select: none". 4332 m_activeMatchIndex = 0; 4333 m_activeMatch = 0; 4334 } else { 4335 // Mark current match "active". 4336 if (forward) { 4337 ++m_activeMatchIndex; 4338 if (m_activeMatchIndex == m_matchCount) 4339 m_activeMatchIndex = 0; 4340 } else { 4341 if (m_activeMatchIndex == 0) 4342 m_activeMatchIndex = m_matchCount; 4343 --m_activeMatchIndex; 4344 } 4345 m_activeMatch = selection.firstRange(); 4346 m_mainFrame->document()->markers()->setMarkersActive( 4347 m_activeMatch.get(), true); 4348 m_mainFrame->selection()->revealSelection( 4349 ScrollAlignment::alignCenterIfNeeded, true); 4350 } 4351 } 4352 4353 // Clear selection so it doesn't display. 4354 m_mainFrame->selection()->clear(); 4355 client->setUiGeneratedSelectionChange(false); 4356 return m_activeMatchIndex; 4357} 4358 4359String WebViewCore::getText(int startX, int startY, int endX, int endY) 4360{ 4361 String text; 4362 4363 Vector<VisibleSelection> ranges = 4364 getTextRanges(startX, startY, endX, endY); 4365 4366 for (size_t i = 0; i < ranges.size(); i++) { 4367 const VisibleSelection& selection = ranges[i]; 4368 if (selection.isRange()) { 4369 PassRefPtr<Range> range = selection.firstRange(); 4370 String textInRange = range->text(); 4371 if (textInRange.length() > 0) { 4372 if (text.length() > 0) 4373 text.append('\n'); 4374 text.append(textInRange); 4375 } 4376 } 4377 } 4378 4379 return text; 4380} 4381 4382/** 4383 * Read the persistent locale. 4384 */ 4385void WebViewCore::getLocale(String& language, String& region) 4386{ 4387 char propLang[PROPERTY_VALUE_MAX], propRegn[PROPERTY_VALUE_MAX]; 4388 4389 property_get("persist.sys.language", propLang, ""); 4390 property_get("persist.sys.country", propRegn, ""); 4391 if (*propLang == 0 && *propRegn == 0) { 4392 /* Set to ro properties, default is en_US */ 4393 property_get("ro.product.locale.language", propLang, "en"); 4394 property_get("ro.product.locale.region", propRegn, "US"); 4395 } 4396 language = String(propLang, 2); 4397 region = String(propRegn, 2); 4398} 4399 4400void WebViewCore::updateLocale() 4401{ 4402 static String prevLang; 4403 static String prevRegn; 4404 String language; 4405 String region; 4406 4407 getLocale(language, region); 4408 4409 if ((language != prevLang) || (region != prevRegn)) { 4410 prevLang = language; 4411 prevRegn = region; 4412 GlyphPageTreeNode::resetRoots(); 4413 fontCache()->invalidate(); 4414 } 4415} 4416 4417//---------------------------------------------------------------------- 4418// Native JNI methods 4419//---------------------------------------------------------------------- 4420static void RevealSelection(JNIEnv* env, jobject obj, jint nativeClass) 4421{ 4422 reinterpret_cast<WebViewCore*>(nativeClass)->revealSelection(); 4423} 4424 4425static jstring RequestLabel(JNIEnv* env, jobject obj, jint nativeClass, 4426 int framePointer, int nodePointer) 4427{ 4428 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4429 return wtfStringToJstring(env, viewImpl->requestLabel( 4430 (WebCore::Frame*) framePointer, (WebCore::Node*) nodePointer)); 4431} 4432 4433static void ClearContent(JNIEnv* env, jobject obj, jint nativeClass) 4434{ 4435 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4436 viewImpl->clearContent(); 4437} 4438 4439static void SetSize(JNIEnv* env, jobject obj, jint nativeClass, jint width, 4440 jint height, jint textWrapWidth, jfloat scale, jint screenWidth, 4441 jint screenHeight, jint anchorX, jint anchorY, jboolean ignoreHeight) 4442{ 4443 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4444 ALOGV("webviewcore::nativeSetSize(%u %u)\n viewImpl: %p", (unsigned)width, (unsigned)height, viewImpl); 4445 ALOG_ASSERT(viewImpl, "viewImpl not set in nativeSetSize"); 4446 viewImpl->setSizeScreenWidthAndScale(width, height, textWrapWidth, scale, 4447 screenWidth, screenHeight, anchorX, anchorY, ignoreHeight); 4448} 4449 4450static void SetScrollOffset(JNIEnv* env, jobject obj, jint nativeClass, 4451 jboolean sendScrollEvent, jint x, jint y) 4452{ 4453 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4454 ALOG_ASSERT(viewImpl, "need viewImpl"); 4455 4456 viewImpl->setScrollOffset(sendScrollEvent, x, y); 4457} 4458 4459static void SetGlobalBounds(JNIEnv* env, jobject obj, jint nativeClass, 4460 jint x, jint y, jint h, jint v) 4461{ 4462 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4463 ALOG_ASSERT(viewImpl, "need viewImpl"); 4464 4465 viewImpl->setGlobalBounds(x, y, h, v); 4466} 4467 4468static jboolean Key(JNIEnv* env, jobject obj, jint nativeClass, jint keyCode, 4469 jint unichar, jint repeatCount, jboolean isShift, jboolean isAlt, 4470 jboolean isSym, jboolean isDown) 4471{ 4472 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4473 return viewImpl->key(PlatformKeyboardEvent(keyCode, 4474 unichar, repeatCount, isDown, isShift, isAlt, isSym)); 4475} 4476 4477static void Click(JNIEnv* env, jobject obj, jint nativeClass, int framePtr, 4478 int nodePtr, jboolean fake) 4479{ 4480 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4481 ALOG_ASSERT(viewImpl, "viewImpl not set in Click"); 4482 4483 viewImpl->click(reinterpret_cast<WebCore::Frame*>(framePtr), 4484 reinterpret_cast<WebCore::Node*>(nodePtr), fake); 4485} 4486 4487static void ContentInvalidateAll(JNIEnv* env, jobject obj, jint nativeClass) 4488{ 4489 reinterpret_cast<WebViewCore*>(nativeClass)->contentInvalidateAll(); 4490} 4491 4492static void DeleteSelection(JNIEnv* env, jobject obj, jint nativeClass, 4493 jint start, jint end, jint textGeneration) 4494{ 4495 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4496 viewImpl->deleteSelection(start, end, textGeneration); 4497} 4498 4499static void SetSelection(JNIEnv* env, jobject obj, jint nativeClass, 4500 jint start, jint end) 4501{ 4502 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4503 viewImpl->setSelection(start, end); 4504} 4505 4506static jstring ModifySelection(JNIEnv* env, jobject obj, jint nativeClass, 4507 jint direction, jint granularity) 4508{ 4509 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4510 String selectionString = viewImpl->modifySelection(direction, granularity); 4511 return wtfStringToJstring(env, selectionString); 4512} 4513 4514static void ReplaceTextfieldText(JNIEnv* env, jobject obj, jint nativeClass, 4515 jint oldStart, jint oldEnd, jstring replace, jint start, jint end, 4516 jint textGeneration) 4517{ 4518 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4519 WTF::String webcoreString = jstringToWtfString(env, replace); 4520 viewImpl->replaceTextfieldText(oldStart, 4521 oldEnd, webcoreString, start, end, textGeneration); 4522} 4523 4524static void PassToJs(JNIEnv* env, jobject obj, jint nativeClass, 4525 jint generation, jstring currentText, jint keyCode, 4526 jint keyValue, jboolean down, jboolean cap, jboolean fn, jboolean sym) 4527{ 4528 WTF::String current = jstringToWtfString(env, currentText); 4529 reinterpret_cast<WebViewCore*>(nativeClass)->passToJs(generation, current, 4530 PlatformKeyboardEvent(keyCode, keyValue, 0, down, cap, fn, sym)); 4531} 4532 4533static void ScrollFocusedTextInput(JNIEnv* env, jobject obj, jint nativeClass, 4534 jfloat xPercent, jint y, jobject contentBounds) 4535{ 4536 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4537 IntRect bounds = viewImpl->scrollFocusedTextInput(xPercent, y); 4538 if (contentBounds) 4539 GraphicsJNI::irect_to_jrect(bounds, env, contentBounds); 4540} 4541 4542static void SetFocusControllerActive(JNIEnv* env, jobject obj, jint nativeClass, 4543 jboolean active) 4544{ 4545 ALOGV("webviewcore::nativeSetFocusControllerActive()\n"); 4546 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4547 ALOG_ASSERT(viewImpl, "viewImpl not set in nativeSetFocusControllerActive"); 4548 viewImpl->setFocusControllerActive(active); 4549} 4550 4551static void SaveDocumentState(JNIEnv* env, jobject obj, jint nativeClass) 4552{ 4553 ALOGV("webviewcore::nativeSaveDocumentState()\n"); 4554 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4555 ALOG_ASSERT(viewImpl, "viewImpl not set in nativeSaveDocumentState"); 4556 viewImpl->saveDocumentState(viewImpl->focusedFrame()); 4557} 4558 4559void WebViewCore::addVisitedLink(const UChar* string, int length) 4560{ 4561 if (m_groupForVisitedLinks) 4562 m_groupForVisitedLinks->addVisitedLink(string, length); 4563} 4564 4565static void NotifyAnimationStarted(JNIEnv* env, jobject obj, jint nativeClass) 4566{ 4567 WebViewCore* viewImpl = (WebViewCore*) nativeClass; 4568 viewImpl->notifyAnimationStarted(); 4569} 4570 4571static jint RecordContent(JNIEnv* env, jobject obj, jint nativeClass, 4572 jobject region, jobject pt) 4573{ 4574 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4575 SkRegion* nativeRegion = GraphicsJNI::getNativeRegion(env, region); 4576 SkIPoint nativePt; 4577 BaseLayerAndroid* result = viewImpl->recordContent(nativeRegion, &nativePt); 4578 GraphicsJNI::ipoint_to_jpoint(nativePt, env, pt); 4579 return reinterpret_cast<jint>(result); 4580} 4581 4582static void SplitContent(JNIEnv* env, jobject obj, jint nativeClass, 4583 jint content) 4584{ 4585 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4586 viewImpl->splitContent(reinterpret_cast<PictureSet*>(content)); 4587} 4588 4589static void SendListBoxChoice(JNIEnv* env, jobject obj, jint nativeClass, 4590 jint choice) 4591{ 4592 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4593 ALOG_ASSERT(viewImpl, "viewImpl not set in nativeSendListBoxChoice"); 4594 viewImpl->popupReply(choice); 4595} 4596 4597// Set aside a predetermined amount of space in which to place the listbox 4598// choices, to avoid unnecessary allocations. 4599// The size here is arbitrary. We want the size to be at least as great as the 4600// number of items in the average multiple-select listbox. 4601#define PREPARED_LISTBOX_STORAGE 10 4602 4603static void SendListBoxChoices(JNIEnv* env, jobject obj, jint nativeClass, 4604 jbooleanArray jArray, jint size) 4605{ 4606 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4607 ALOG_ASSERT(viewImpl, "viewImpl not set in nativeSendListBoxChoices"); 4608 jboolean* ptrArray = env->GetBooleanArrayElements(jArray, 0); 4609 SkAutoSTMalloc<PREPARED_LISTBOX_STORAGE, int> storage(size); 4610 int* array = storage.get(); 4611 int count = 0; 4612 for (int i = 0; i < size; i++) { 4613 if (ptrArray[i]) { 4614 array[count++] = i; 4615 } 4616 } 4617 env->ReleaseBooleanArrayElements(jArray, ptrArray, JNI_ABORT); 4618 viewImpl->popupReply(array, count); 4619} 4620 4621// TODO: Move this to WebView.cpp since it is only needed there 4622static jstring FindAddress(JNIEnv* env, jobject obj, jstring addr, 4623 jboolean caseInsensitive) 4624{ 4625 if (!addr) 4626 return 0; 4627 int length = env->GetStringLength(addr); 4628 if (!length) 4629 return 0; 4630 const jchar* addrChars = env->GetStringChars(addr, 0); 4631 size_t start, end; 4632 AddressDetector detector; 4633 bool success = detector.FindContent(addrChars, addrChars + length, &start, &end); 4634 jstring ret = 0; 4635 if (success) 4636 ret = env->NewString(addrChars + start, end - start); 4637 env->ReleaseStringChars(addr, addrChars); 4638 return ret; 4639} 4640 4641static jboolean HandleTouchEvent(JNIEnv* env, jobject obj, jint nativeClass, 4642 jint action, jintArray idArray, jintArray xArray, jintArray yArray, 4643 jint count, jint actionIndex, jint metaState) 4644{ 4645 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4646 ALOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); 4647 jint* ptrIdArray = env->GetIntArrayElements(idArray, 0); 4648 jint* ptrXArray = env->GetIntArrayElements(xArray, 0); 4649 jint* ptrYArray = env->GetIntArrayElements(yArray, 0); 4650 Vector<int> ids(count); 4651 Vector<IntPoint> points(count); 4652 for (int c = 0; c < count; c++) { 4653 ids[c] = ptrIdArray[c]; 4654 points[c].setX(ptrXArray[c]); 4655 points[c].setY(ptrYArray[c]); 4656 } 4657 env->ReleaseIntArrayElements(idArray, ptrIdArray, JNI_ABORT); 4658 env->ReleaseIntArrayElements(xArray, ptrXArray, JNI_ABORT); 4659 env->ReleaseIntArrayElements(yArray, ptrYArray, JNI_ABORT); 4660 4661 return viewImpl->handleTouchEvent(action, ids, points, actionIndex, metaState); 4662} 4663 4664static void TouchUp(JNIEnv* env, jobject obj, jint nativeClass, 4665 jint touchGeneration, jint frame, jint node, jint x, jint y) 4666{ 4667 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4668 ALOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); 4669 viewImpl->touchUp(touchGeneration, 4670 (WebCore::Frame*) frame, (WebCore::Node*) node, x, y); 4671} 4672 4673static bool MouseClick(JNIEnv* env, jobject obj, jint nativeClass) 4674{ 4675 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4676 return viewImpl->performMouseClick(); 4677} 4678 4679static jstring RetrieveHref(JNIEnv* env, jobject obj, jint nativeClass, 4680 jint x, jint y) 4681{ 4682 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4683 ALOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); 4684 WTF::String result = viewImpl->retrieveHref(x, y); 4685 if (!result.isEmpty()) 4686 return wtfStringToJstring(env, result); 4687 return 0; 4688} 4689 4690static jstring RetrieveAnchorText(JNIEnv* env, jobject obj, jint nativeClass, 4691 jint x, jint y) 4692{ 4693 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4694 ALOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); 4695 WTF::String result = viewImpl->retrieveAnchorText(x, y); 4696 if (!result.isEmpty()) 4697 return wtfStringToJstring(env, result); 4698 return 0; 4699} 4700 4701static jstring RetrieveImageSource(JNIEnv* env, jobject obj, jint nativeClass, 4702 jint x, jint y) 4703{ 4704 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4705 WTF::String result = viewImpl->retrieveImageSource(x, y); 4706 return !result.isEmpty() ? wtfStringToJstring(env, result) : 0; 4707} 4708 4709static void MoveMouse(JNIEnv* env, jobject obj, jint nativeClass, jint x, jint y) 4710{ 4711 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4712 ALOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); 4713 viewImpl->moveMouse(x, y); 4714} 4715 4716static jint GetContentMinPrefWidth(JNIEnv* env, jobject obj, jint nativeClass) 4717{ 4718 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4719 ALOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); 4720 4721 WebCore::Frame* frame = viewImpl->mainFrame(); 4722 if (frame) { 4723 WebCore::Document* document = frame->document(); 4724 if (document) { 4725 WebCore::RenderObject* renderer = document->renderer(); 4726 if (renderer && renderer->isRenderView()) { 4727 return renderer->minPreferredLogicalWidth(); 4728 } 4729 } 4730 } 4731 return 0; 4732} 4733 4734static void SetViewportSettingsFromNative(JNIEnv* env, jobject obj, 4735 jint nativeClass) 4736{ 4737 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4738 ALOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); 4739 4740 WebCore::Settings* s = viewImpl->mainFrame()->page()->settings(); 4741 if (!s) 4742 return; 4743 4744#ifdef ANDROID_META_SUPPORT 4745 env->SetIntField(obj, gWebViewCoreFields.m_viewportWidth, s->viewportWidth()); 4746 env->SetIntField(obj, gWebViewCoreFields.m_viewportHeight, s->viewportHeight()); 4747 env->SetIntField(obj, gWebViewCoreFields.m_viewportInitialScale, s->viewportInitialScale()); 4748 env->SetIntField(obj, gWebViewCoreFields.m_viewportMinimumScale, s->viewportMinimumScale()); 4749 env->SetIntField(obj, gWebViewCoreFields.m_viewportMaximumScale, s->viewportMaximumScale()); 4750 env->SetBooleanField(obj, gWebViewCoreFields.m_viewportUserScalable, s->viewportUserScalable()); 4751 env->SetIntField(obj, gWebViewCoreFields.m_viewportDensityDpi, s->viewportTargetDensityDpi()); 4752#endif 4753} 4754 4755static void SetBackgroundColor(JNIEnv* env, jobject obj, jint nativeClass, 4756 jint color) 4757{ 4758 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4759 ALOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); 4760 4761 viewImpl->setBackgroundColor((SkColor) color); 4762} 4763 4764static void DumpDomTree(JNIEnv* env, jobject obj, jint nativeClass, 4765 jboolean useFile) 4766{ 4767 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4768 ALOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); 4769 4770 viewImpl->dumpDomTree(useFile); 4771} 4772 4773static void DumpRenderTree(JNIEnv* env, jobject obj, jint nativeClass, 4774 jboolean useFile) 4775{ 4776 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4777 ALOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); 4778 4779 viewImpl->dumpRenderTree(useFile); 4780} 4781 4782static void SetJsFlags(JNIEnv* env, jobject obj, jint nativeClass, jstring flags) 4783{ 4784 WTF::String flagsString = jstringToWtfString(env, flags); 4785 WTF::CString utf8String = flagsString.utf8(); 4786 WebCore::ScriptController::setFlags(utf8String.data(), utf8String.length()); 4787} 4788 4789 4790// Called from the Java side to set a new quota for the origin or new appcache 4791// max size in response to a notification that the original quota was exceeded or 4792// that the appcache has reached its maximum size. 4793static void SetNewStorageLimit(JNIEnv* env, jobject obj, jint nativeClass, 4794 jlong quota) 4795{ 4796#if ENABLE(DATABASE) || ENABLE(OFFLINE_WEB_APPLICATIONS) 4797 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4798 Frame* frame = viewImpl->mainFrame(); 4799 4800 // The main thread is blocked awaiting this response, so now we can wake it 4801 // up. 4802 ChromeClientAndroid* chromeC = static_cast<ChromeClientAndroid*>(frame->page()->chrome()->client()); 4803 chromeC->wakeUpMainThreadWithNewQuota(quota); 4804#endif 4805} 4806 4807// Called from Java to provide a Geolocation permission state for the specified origin. 4808static void GeolocationPermissionsProvide(JNIEnv* env, jobject obj, 4809 jint nativeClass, jstring origin, jboolean allow, jboolean remember) 4810{ 4811 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4812 Frame* frame = viewImpl->mainFrame(); 4813 4814 ChromeClientAndroid* chromeClient = static_cast<ChromeClientAndroid*>(frame->page()->chrome()->client()); 4815 chromeClient->provideGeolocationPermissions(jstringToWtfString(env, origin), allow, remember); 4816} 4817 4818static void RegisterURLSchemeAsLocal(JNIEnv* env, jobject obj, jint nativeClass, 4819 jstring scheme) 4820{ 4821 WebCore::SchemeRegistry::registerURLSchemeAsLocal(jstringToWtfString(env, scheme)); 4822} 4823 4824static bool FocusBoundsChanged(JNIEnv* env, jobject obj, jint nativeClass) 4825{ 4826 return reinterpret_cast<WebViewCore*>(nativeClass)->focusBoundsChanged(); 4827} 4828 4829static void SetIsPaused(JNIEnv* env, jobject obj, jint nativeClass, 4830 jboolean isPaused) 4831{ 4832 // tell the webcore thread to stop thinking while we do other work 4833 // (selection and scrolling). This has nothing to do with the lifecycle 4834 // pause and resume. 4835 reinterpret_cast<WebViewCore*>(nativeClass)->setIsPaused(isPaused); 4836} 4837 4838static void Pause(JNIEnv* env, jobject obj, jint nativeClass) 4839{ 4840 // This is called for the foreground tab when the browser is put to the 4841 // background (and also for any tab when it is put to the background of the 4842 // browser). The browser can only be killed by the system when it is in the 4843 // background, so saving the Geolocation permission state now ensures that 4844 // is maintained when the browser is killed. 4845 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4846 ChromeClient* chromeClient = viewImpl->mainFrame()->page()->chrome()->client(); 4847 ChromeClientAndroid* chromeClientAndroid = static_cast<ChromeClientAndroid*>(chromeClient); 4848 chromeClientAndroid->storeGeolocationPermissions(); 4849 4850 Frame* mainFrame = viewImpl->mainFrame(); 4851 for (Frame* frame = mainFrame; frame; frame = frame->tree()->traverseNext()) { 4852 Geolocation* geolocation = frame->domWindow()->navigator()->optionalGeolocation(); 4853 if (geolocation) 4854 geolocation->suspend(); 4855 } 4856 4857 viewImpl->deviceMotionAndOrientationManager()->maybeSuspendClients(); 4858 4859 ANPEvent event; 4860 SkANP::InitEvent(&event, kLifecycle_ANPEventType); 4861 event.data.lifecycle.action = kPause_ANPLifecycleAction; 4862 viewImpl->sendPluginEvent(event); 4863 4864 viewImpl->setIsPaused(true); 4865} 4866 4867static void Resume(JNIEnv* env, jobject obj, jint nativeClass) 4868{ 4869 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4870 Frame* mainFrame = viewImpl->mainFrame(); 4871 for (Frame* frame = mainFrame; frame; frame = frame->tree()->traverseNext()) { 4872 Geolocation* geolocation = frame->domWindow()->navigator()->optionalGeolocation(); 4873 if (geolocation) 4874 geolocation->resume(); 4875 } 4876 4877 viewImpl->deviceMotionAndOrientationManager()->maybeResumeClients(); 4878 4879 ANPEvent event; 4880 SkANP::InitEvent(&event, kLifecycle_ANPEventType); 4881 event.data.lifecycle.action = kResume_ANPLifecycleAction; 4882 viewImpl->sendPluginEvent(event); 4883 4884 viewImpl->setIsPaused(false); 4885} 4886 4887static void FreeMemory(JNIEnv* env, jobject obj, jint nativeClass) 4888{ 4889 ANPEvent event; 4890 SkANP::InitEvent(&event, kLifecycle_ANPEventType); 4891 event.data.lifecycle.action = kFreeMemory_ANPLifecycleAction; 4892 reinterpret_cast<WebViewCore*>(nativeClass)->sendPluginEvent(event); 4893} 4894 4895static void ProvideVisitedHistory(JNIEnv* env, jobject obj, jint nativeClass, 4896 jobject hist) 4897{ 4898 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4899 ALOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); 4900 4901 jobjectArray array = static_cast<jobjectArray>(hist); 4902 4903 jsize len = env->GetArrayLength(array); 4904 for (jsize i = 0; i < len; i++) { 4905 jstring item = static_cast<jstring>(env->GetObjectArrayElement(array, i)); 4906 const UChar* str = static_cast<const UChar*>(env->GetStringChars(item, 0)); 4907 jsize len = env->GetStringLength(item); 4908 viewImpl->addVisitedLink(str, len); 4909 env->ReleaseStringChars(item, str); 4910 env->DeleteLocalRef(item); 4911 } 4912} 4913 4914static void PluginSurfaceReady(JNIEnv* env, jobject obj, jint nativeClass) 4915{ 4916 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4917 if (viewImpl) 4918 viewImpl->sendPluginSurfaceReady(); 4919} 4920 4921// Notification from the UI thread that the plugin's full-screen surface has been discarded 4922static void FullScreenPluginHidden(JNIEnv* env, jobject obj, jint nativeClass, 4923 jint npp) 4924{ 4925 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4926 PluginWidgetAndroid* plugin = viewImpl->getPluginWidget((NPP)npp); 4927 if (plugin) 4928 plugin->exitFullScreen(false); 4929} 4930 4931static WebCore::IntRect jrect_to_webrect(JNIEnv* env, jobject obj) 4932{ 4933 int L, T, R, B; 4934 GraphicsJNI::get_jrect(env, obj, &L, &T, &R, &B); 4935 return WebCore::IntRect(L, T, R - L, B - T); 4936} 4937 4938static jobject HitTest(JNIEnv* env, jobject obj, jint nativeClass, jint x, 4939 jint y, jint slop, jboolean doMoveMouse) 4940{ 4941 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4942 if (!viewImpl) 4943 return 0; 4944 AndroidHitTestResult result = viewImpl->hitTestAtPoint(x, y, slop, doMoveMouse); 4945 return result.createJavaObject(env); 4946} 4947 4948static void AutoFillForm(JNIEnv* env, jobject obj, jint nativeClass, 4949 jint queryId) 4950{ 4951#if ENABLE(WEB_AUTOFILL) 4952 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4953 if (!viewImpl) 4954 return; 4955 4956 WebCore::Frame* frame = viewImpl->mainFrame(); 4957 if (frame) { 4958 EditorClientAndroid* editorC = static_cast<EditorClientAndroid*>(frame->page()->editorClient()); 4959 WebAutofill* autoFill = editorC->getAutofill(); 4960 autoFill->fillFormFields(queryId); 4961 } 4962#endif 4963} 4964 4965static void CloseIdleConnections(JNIEnv* env, jobject obj, jint nativeClass) 4966{ 4967 WebCache::get(true)->closeIdleConnections(); 4968 WebCache::get(false)->closeIdleConnections(); 4969} 4970 4971static void nativeCertTrustChanged(JNIEnv *env, jobject obj) 4972{ 4973#if USE(CHROME_NETWORK_STACK) 4974 WebCache::get(true)->certTrustChanged(); 4975 WebCache::get(false)->certTrustChanged(); 4976#endif 4977} 4978 4979static void ScrollRenderLayer(JNIEnv* env, jobject obj, jint nativeClass, 4980 jint layer, jobject jRect) 4981{ 4982 SkRect rect; 4983 GraphicsJNI::jrect_to_rect(env, jRect, &rect); 4984 reinterpret_cast<WebViewCore*>(nativeClass)->scrollRenderLayer(layer, rect); 4985} 4986 4987static void DeleteText(JNIEnv* env, jobject obj, jint nativeClass, 4988 jint startX, jint startY, jint endX, jint endY) 4989{ 4990 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4991 viewImpl->deleteText(startX, startY, endX, endY); 4992} 4993 4994static void InsertText(JNIEnv* env, jobject obj, jint nativeClass, 4995 jstring text) 4996{ 4997 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4998 WTF::String wtfText = jstringToWtfString(env, text); 4999 viewImpl->insertText(wtfText); 5000} 5001 5002static jobject GetText(JNIEnv* env, jobject obj, jint nativeClass, 5003 jint startX, jint startY, jint endX, jint endY) 5004{ 5005 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 5006 WTF::String text = viewImpl->getText(startX, startY, endX, endY); 5007 return text.isEmpty() ? 0 : wtfStringToJstring(env, text); 5008} 5009 5010static void SelectText(JNIEnv* env, jobject obj, jint nativeClass, 5011 jint startX, jint startY, jint endX, jint endY) 5012{ 5013 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 5014 viewImpl->selectText(startX, startY, endX, endY); 5015} 5016 5017static void ClearSelection(JNIEnv* env, jobject obj, jint nativeClass) 5018{ 5019 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 5020 viewImpl->focusedFrame()->selection()->clear(); 5021} 5022 5023static bool SelectWordAt(JNIEnv* env, jobject obj, jint nativeClass, jint x, jint y) 5024{ 5025 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 5026 return viewImpl->selectWordAt(x, y); 5027} 5028 5029static void SelectAll(JNIEnv* env, jobject obj, jint nativeClass) 5030{ 5031 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 5032 viewImpl->focusedFrame()->selection()->selectAll(); 5033} 5034 5035static int FindAll(JNIEnv* env, jobject obj, jint nativeClass, 5036 jstring text) 5037{ 5038 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 5039 WTF::String wtfText = jstringToWtfString(env, text); 5040 return viewImpl->findTextOnPage(wtfText); 5041} 5042 5043static int FindNext(JNIEnv* env, jobject obj, jint nativeClass, 5044 jboolean forward) 5045{ 5046 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 5047 return viewImpl->findNextOnPage(forward); 5048} 5049 5050// ---------------------------------------------------------------------------- 5051 5052/* 5053 * JNI registration. 5054 */ 5055static JNINativeMethod gJavaWebViewCoreMethods[] = { 5056 { "nativeClearContent", "(I)V", 5057 (void*) ClearContent }, 5058 { "nativeFocusBoundsChanged", "(I)Z", 5059 (void*) FocusBoundsChanged } , 5060 { "nativeKey", "(IIIIZZZZ)Z", 5061 (void*) Key }, 5062 { "nativeClick", "(IIIZ)V", 5063 (void*) Click }, 5064 { "nativeContentInvalidateAll", "(I)V", 5065 (void*) ContentInvalidateAll }, 5066 { "nativeSendListBoxChoices", "(I[ZI)V", 5067 (void*) SendListBoxChoices }, 5068 { "nativeSendListBoxChoice", "(II)V", 5069 (void*) SendListBoxChoice }, 5070 { "nativeSetSize", "(IIIIFIIIIZ)V", 5071 (void*) SetSize }, 5072 { "nativeSetScrollOffset", "(IZII)V", 5073 (void*) SetScrollOffset }, 5074 { "nativeSetGlobalBounds", "(IIIII)V", 5075 (void*) SetGlobalBounds }, 5076 { "nativeSetSelection", "(III)V", 5077 (void*) SetSelection } , 5078 { "nativeModifySelection", "(III)Ljava/lang/String;", 5079 (void*) ModifySelection }, 5080 { "nativeDeleteSelection", "(IIII)V", 5081 (void*) DeleteSelection } , 5082 { "nativeReplaceTextfieldText", "(IIILjava/lang/String;III)V", 5083 (void*) ReplaceTextfieldText } , 5084 { "nativeMoveMouse", "(III)V", 5085 (void*) MoveMouse }, 5086 { "passToJs", "(IILjava/lang/String;IIZZZZ)V", 5087 (void*) PassToJs }, 5088 { "nativeScrollFocusedTextInput", "(IFILandroid/graphics/Rect;)V", 5089 (void*) ScrollFocusedTextInput }, 5090 { "nativeSetFocusControllerActive", "(IZ)V", 5091 (void*) SetFocusControllerActive }, 5092 { "nativeSaveDocumentState", "(I)V", 5093 (void*) SaveDocumentState }, 5094 { "nativeFindAddress", "(Ljava/lang/String;Z)Ljava/lang/String;", 5095 (void*) FindAddress }, 5096 { "nativeHandleTouchEvent", "(II[I[I[IIII)Z", 5097 (void*) HandleTouchEvent }, 5098 { "nativeTouchUp", "(IIIIII)V", 5099 (void*) TouchUp }, 5100 { "nativeMouseClick", "(I)Z", 5101 (void*) MouseClick }, 5102 { "nativeRetrieveHref", "(III)Ljava/lang/String;", 5103 (void*) RetrieveHref }, 5104 { "nativeRetrieveAnchorText", "(III)Ljava/lang/String;", 5105 (void*) RetrieveAnchorText }, 5106 { "nativeRetrieveImageSource", "(III)Ljava/lang/String;", 5107 (void*) RetrieveImageSource }, 5108 { "nativeGetContentMinPrefWidth", "(I)I", 5109 (void*) GetContentMinPrefWidth }, 5110 { "nativeNotifyAnimationStarted", "(I)V", 5111 (void*) NotifyAnimationStarted }, 5112 { "nativeRecordContent", "(ILandroid/graphics/Region;Landroid/graphics/Point;)I", 5113 (void*) RecordContent }, 5114 { "setViewportSettingsFromNative", "(I)V", 5115 (void*) SetViewportSettingsFromNative }, 5116 { "nativeSplitContent", "(II)V", 5117 (void*) SplitContent }, 5118 { "nativeSetBackgroundColor", "(II)V", 5119 (void*) SetBackgroundColor }, 5120 { "nativeRegisterURLSchemeAsLocal", "(ILjava/lang/String;)V", 5121 (void*) RegisterURLSchemeAsLocal }, 5122 { "nativeDumpDomTree", "(IZ)V", 5123 (void*) DumpDomTree }, 5124 { "nativeDumpRenderTree", "(IZ)V", 5125 (void*) DumpRenderTree }, 5126 { "nativeSetNewStorageLimit", "(IJ)V", 5127 (void*) SetNewStorageLimit }, 5128 { "nativeGeolocationPermissionsProvide", "(ILjava/lang/String;ZZ)V", 5129 (void*) GeolocationPermissionsProvide }, 5130 { "nativeSetIsPaused", "(IZ)V", (void*) SetIsPaused }, 5131 { "nativePause", "(I)V", (void*) Pause }, 5132 { "nativeResume", "(I)V", (void*) Resume }, 5133 { "nativeFreeMemory", "(I)V", (void*) FreeMemory }, 5134 { "nativeSetJsFlags", "(ILjava/lang/String;)V", (void*) SetJsFlags }, 5135 { "nativeRequestLabel", "(III)Ljava/lang/String;", 5136 (void*) RequestLabel }, 5137 { "nativeRevealSelection", "(I)V", (void*) RevealSelection }, 5138 { "nativeProvideVisitedHistory", "(I[Ljava/lang/String;)V", 5139 (void*) ProvideVisitedHistory }, 5140 { "nativeFullScreenPluginHidden", "(II)V", 5141 (void*) FullScreenPluginHidden }, 5142 { "nativePluginSurfaceReady", "(I)V", 5143 (void*) PluginSurfaceReady }, 5144 { "nativeHitTest", "(IIIIZ)Landroid/webkit/WebViewCore$WebKitHitTest;", 5145 (void*) HitTest }, 5146 { "nativeAutoFillForm", "(II)V", 5147 (void*) AutoFillForm }, 5148 { "nativeScrollLayer", "(IILandroid/graphics/Rect;)V", 5149 (void*) ScrollRenderLayer }, 5150 { "nativeCloseIdleConnections", "(I)V", 5151 (void*) CloseIdleConnections }, 5152 { "nativeDeleteText", "(IIIII)V", 5153 (void*) DeleteText }, 5154 { "nativeInsertText", "(ILjava/lang/String;)V", 5155 (void*) InsertText }, 5156 { "nativeGetText", "(IIIII)Ljava/lang/String;", 5157 (void*) GetText }, 5158 { "nativeSelectText", "(IIIII)V", 5159 (void*) SelectText }, 5160 { "nativeClearTextSelection", "(I)V", 5161 (void*) ClearSelection }, 5162 { "nativeSelectWordAt", "(III)Z", 5163 (void*) SelectWordAt }, 5164 { "nativeSelectAll", "(I)V", 5165 (void*) SelectAll }, 5166 { "nativeCertTrustChanged","()V", 5167 (void*) nativeCertTrustChanged }, 5168 { "nativeFindAll", "(ILjava/lang/String;)I", 5169 (void*) FindAll }, 5170 { "nativeFindNext", "(IZ)I", 5171 (void*) FindNext }, 5172}; 5173 5174int registerWebViewCore(JNIEnv* env) 5175{ 5176 jclass widget = env->FindClass("android/webkit/WebViewCore"); 5177 ALOG_ASSERT(widget, 5178 "Unable to find class android/webkit/WebViewCore"); 5179 gWebViewCoreFields.m_nativeClass = env->GetFieldID(widget, "mNativeClass", 5180 "I"); 5181 ALOG_ASSERT(gWebViewCoreFields.m_nativeClass, 5182 "Unable to find android/webkit/WebViewCore.mNativeClass"); 5183 gWebViewCoreFields.m_viewportWidth = env->GetFieldID(widget, 5184 "mViewportWidth", "I"); 5185 ALOG_ASSERT(gWebViewCoreFields.m_viewportWidth, 5186 "Unable to find android/webkit/WebViewCore.mViewportWidth"); 5187 gWebViewCoreFields.m_viewportHeight = env->GetFieldID(widget, 5188 "mViewportHeight", "I"); 5189 ALOG_ASSERT(gWebViewCoreFields.m_viewportHeight, 5190 "Unable to find android/webkit/WebViewCore.mViewportHeight"); 5191 gWebViewCoreFields.m_viewportInitialScale = env->GetFieldID(widget, 5192 "mViewportInitialScale", "I"); 5193 ALOG_ASSERT(gWebViewCoreFields.m_viewportInitialScale, 5194 "Unable to find android/webkit/WebViewCore.mViewportInitialScale"); 5195 gWebViewCoreFields.m_viewportMinimumScale = env->GetFieldID(widget, 5196 "mViewportMinimumScale", "I"); 5197 ALOG_ASSERT(gWebViewCoreFields.m_viewportMinimumScale, 5198 "Unable to find android/webkit/WebViewCore.mViewportMinimumScale"); 5199 gWebViewCoreFields.m_viewportMaximumScale = env->GetFieldID(widget, 5200 "mViewportMaximumScale", "I"); 5201 ALOG_ASSERT(gWebViewCoreFields.m_viewportMaximumScale, 5202 "Unable to find android/webkit/WebViewCore.mViewportMaximumScale"); 5203 gWebViewCoreFields.m_viewportUserScalable = env->GetFieldID(widget, 5204 "mViewportUserScalable", "Z"); 5205 ALOG_ASSERT(gWebViewCoreFields.m_viewportUserScalable, 5206 "Unable to find android/webkit/WebViewCore.mViewportUserScalable"); 5207 gWebViewCoreFields.m_viewportDensityDpi = env->GetFieldID(widget, 5208 "mViewportDensityDpi", "I"); 5209 ALOG_ASSERT(gWebViewCoreFields.m_viewportDensityDpi, 5210 "Unable to find android/webkit/WebViewCore.mViewportDensityDpi"); 5211 gWebViewCoreFields.m_drawIsPaused = env->GetFieldID(widget, 5212 "mDrawIsPaused", "Z"); 5213 ALOG_ASSERT(gWebViewCoreFields.m_drawIsPaused, 5214 "Unable to find android/webkit/WebViewCore.mDrawIsPaused"); 5215 gWebViewCoreFields.m_lowMemoryUsageMb = env->GetFieldID(widget, "mLowMemoryUsageThresholdMb", "I"); 5216 gWebViewCoreFields.m_highMemoryUsageMb = env->GetFieldID(widget, "mHighMemoryUsageThresholdMb", "I"); 5217 gWebViewCoreFields.m_highUsageDeltaMb = env->GetFieldID(widget, "mHighUsageDeltaMb", "I"); 5218 5219 gWebViewCoreStaticMethods.m_isSupportedMediaMimeType = 5220 env->GetStaticMethodID(widget, "isSupportedMediaMimeType", "(Ljava/lang/String;)Z"); 5221 LOG_FATAL_IF(!gWebViewCoreStaticMethods.m_isSupportedMediaMimeType, 5222 "Could not find static method isSupportedMediaMimeType from WebViewCore"); 5223 5224 env->DeleteLocalRef(widget); 5225 5226 return jniRegisterNativeMethods(env, "android/webkit/WebViewCore", 5227 gJavaWebViewCoreMethods, NELEM(gJavaWebViewCoreMethods)); 5228} 5229 5230} /* namespace android */ 5231