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