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