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