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