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