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