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