WebViewCore.cpp revision 7b1ba95f7d592009a5674bbc38e3af9ee83a796a
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 APPLE COMPUTER, INC. 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 "AtomicString.h" 32#include "CachedNode.h" 33#include "CachedRoot.h" 34#include "ChromeClientAndroid.h" 35#include "Color.h" 36#include "DatabaseTracker.h" 37#include "Document.h" 38#include "DOMWindow.h" 39#include "Element.h" 40#include "Editor.h" 41#include "EditorClientAndroid.h" 42#include "EventHandler.h" 43#include "EventNames.h" 44#include "FocusController.h" 45#include "Font.h" 46#include "Frame.h" 47#include "FrameLoader.h" 48#include "FrameLoaderClientAndroid.h" 49#include "FrameTree.h" 50#include "FrameView.h" 51#include "Geolocation.h" 52#include "GraphicsContext.h" 53#include "GraphicsJNI.h" 54#include "HitTestResult.h" 55#include "HTMLAnchorElement.h" 56#include "HTMLAreaElement.h" 57#include "HTMLElement.h" 58#include "HTMLImageElement.h" 59#include "HTMLInputElement.h" 60#include "HTMLMapElement.h" 61#include "HTMLNames.h" 62#include "HTMLOptGroupElement.h" 63#include "HTMLOptionElement.h" 64#include "HTMLSelectElement.h" 65#include "HTMLTextAreaElement.h" 66#include "InlineTextBox.h" 67#include <JNIHelp.h> 68#include "KeyboardCodes.h" 69#include "Navigator.h" 70#include "Node.h" 71#include "Page.h" 72#include "PageGroup.h" 73#include "PlatformKeyboardEvent.h" 74#include "PlatformString.h" 75#include "PluginWidgetAndroid.h" 76#include "PluginView.h" 77#include "Position.h" 78#include "ProgressTracker.h" 79#include "RenderBox.h" 80#include "RenderLayer.h" 81#include "RenderPart.h" 82#include "RenderText.h" 83#include "RenderTextControl.h" 84#include "RenderThemeAndroid.h" 85#include "RenderView.h" 86#include "ResourceRequest.h" 87#include "SelectionController.h" 88#include "Settings.h" 89#include "SkANP.h" 90#include "SkTemplates.h" 91#include "SkTypes.h" 92#include "SkCanvas.h" 93#include "SkPicture.h" 94#include "SkUtils.h" 95#include "StringImpl.h" 96#include "Text.h" 97#include "TypingCommand.h" 98#include "WebCoreFrameBridge.h" 99#include "WebFrameView.h" 100#include "HistoryItem.h" 101#include "android_graphics.h" 102#include <ui/KeycodeLabels.h> 103#include "jni_utility.h" 104#include <wtf/CurrentTime.h> 105 106#if USE(V8) 107#include "CString.h" 108#include "ScriptController.h" 109#endif 110 111#if DEBUG_NAV_UI 112#include "SkTime.h" 113#endif 114 115#if ENABLE(TOUCH_EVENTS) // Android 116#include "PlatformTouchEvent.h" 117#endif 118 119#ifdef ANDROID_DOM_LOGGING 120#include "AndroidLog.h" 121#include "RenderTreeAsText.h" 122#include "CString.h" 123 124FILE* gDomTreeFile = 0; 125FILE* gRenderTreeFile = 0; 126#endif 127 128#ifdef ANDROID_INSTRUMENT 129#include "TimeCounter.h" 130#endif 131 132/* We pass this flag when recording the actual content, so that we don't spend 133 time actually regionizing complex path clips, when all we really want to do 134 is record them. 135 */ 136#define PICT_RECORD_FLAGS SkPicture::kUsePathBoundsForClip_RecordingFlag 137 138//////////////////////////////////////////////////////////////////////////////////////////////// 139 140namespace android { 141 142// ---------------------------------------------------------------------------- 143 144#define GET_NATIVE_VIEW(env, obj) ((WebViewCore*)env->GetIntField(obj, gWebViewCoreFields.m_nativeClass)) 145 146// Field ids for WebViewCore 147struct WebViewCoreFields { 148 jfieldID m_nativeClass; 149 jfieldID m_viewportWidth; 150 jfieldID m_viewportHeight; 151 jfieldID m_viewportInitialScale; 152 jfieldID m_viewportMinimumScale; 153 jfieldID m_viewportMaximumScale; 154 jfieldID m_viewportUserScalable; 155 jfieldID m_viewportDensityDpi; 156 jfieldID m_webView; 157} gWebViewCoreFields; 158 159// ---------------------------------------------------------------------------- 160 161struct WebViewCore::JavaGlue { 162 jobject m_obj; 163 jmethodID m_spawnScrollTo; 164 jmethodID m_scrollTo; 165 jmethodID m_scrollBy; 166 jmethodID m_contentDraw; 167 jmethodID m_requestListBox; 168 jmethodID m_openFileChooser; 169 jmethodID m_requestSingleListBox; 170 jmethodID m_jsAlert; 171 jmethodID m_jsConfirm; 172 jmethodID m_jsPrompt; 173 jmethodID m_jsUnload; 174 jmethodID m_jsInterrupt; 175 jmethodID m_didFirstLayout; 176 jmethodID m_updateViewport; 177 jmethodID m_sendNotifyProgressFinished; 178 jmethodID m_sendViewInvalidate; 179 jmethodID m_updateTextfield; 180 jmethodID m_updateTextSelection; 181 jmethodID m_clearTextEntry; 182 jmethodID m_restoreScale; 183 jmethodID m_restoreScreenWidthScale; 184 jmethodID m_needTouchEvents; 185 jmethodID m_requestKeyboard; 186 jmethodID m_exceededDatabaseQuota; 187 jmethodID m_reachedMaxAppCacheSize; 188 jmethodID m_populateVisitedLinks; 189 jmethodID m_geolocationPermissionsShowPrompt; 190 jmethodID m_geolocationPermissionsHidePrompt; 191 jmethodID m_addMessageToConsole; 192 jmethodID m_startFullScreenPluginActivity; 193 jmethodID m_createSurface; 194 jmethodID m_updateSurface; 195 jmethodID m_destroySurface; 196 jmethodID m_sendFindAgain; 197 AutoJObject object(JNIEnv* env) { 198 return getRealObject(env, m_obj); 199 } 200}; 201 202/* 203 * WebViewCore Implementation 204 */ 205 206static jmethodID GetJMethod(JNIEnv* env, jclass clazz, const char name[], const char signature[]) 207{ 208 jmethodID m = env->GetMethodID(clazz, name, signature); 209 LOG_ASSERT(m, "Could not find method %s", name); 210 return m; 211} 212 213Mutex WebViewCore::gFrameCacheMutex; 214Mutex WebViewCore::gButtonMutex; 215Mutex WebViewCore::gCursorBoundsMutex; 216Mutex WebViewCore::m_contentMutex; 217 218WebViewCore::WebViewCore(JNIEnv* env, jobject javaWebViewCore, WebCore::Frame* mainframe) 219 : m_pluginInvalTimer(this, &WebViewCore::pluginInvalTimerFired) 220{ 221 m_mainFrame = mainframe; 222 223 m_popupReply = 0; 224 m_moveGeneration = 0; 225 m_lastGeneration = 0; 226 m_touchGeneration = 0; 227 m_blockTextfieldUpdates = false; 228 // just initial values. These should be set by client 229 m_maxXScroll = 320/4; 230 m_maxYScroll = 240/4; 231 m_textGeneration = 0; 232 m_screenWidth = 320; 233 m_scale = 1; 234 m_screenWidthScale = 1; 235 236 LOG_ASSERT(m_mainFrame, "Uh oh, somehow a frameview was made without an initial frame!"); 237 238 jclass clazz = env->GetObjectClass(javaWebViewCore); 239 m_javaGlue = new JavaGlue; 240 m_javaGlue->m_obj = adoptGlobalRef(env, javaWebViewCore); 241 m_javaGlue->m_spawnScrollTo = GetJMethod(env, clazz, "contentSpawnScrollTo", "(II)V"); 242 m_javaGlue->m_scrollTo = GetJMethod(env, clazz, "contentScrollTo", "(II)V"); 243 m_javaGlue->m_scrollBy = GetJMethod(env, clazz, "contentScrollBy", "(IIZ)V"); 244 m_javaGlue->m_contentDraw = GetJMethod(env, clazz, "contentDraw", "()V"); 245 m_javaGlue->m_requestListBox = GetJMethod(env, clazz, "requestListBox", "([Ljava/lang/String;[I[I)V"); 246 m_javaGlue->m_openFileChooser = GetJMethod(env, clazz, "openFileChooser", "()Ljava/lang/String;"); 247 m_javaGlue->m_requestSingleListBox = GetJMethod(env, clazz, "requestListBox", "([Ljava/lang/String;[II)V"); 248 m_javaGlue->m_jsAlert = GetJMethod(env, clazz, "jsAlert", "(Ljava/lang/String;Ljava/lang/String;)V"); 249 m_javaGlue->m_jsConfirm = GetJMethod(env, clazz, "jsConfirm", "(Ljava/lang/String;Ljava/lang/String;)Z"); 250 m_javaGlue->m_jsPrompt = GetJMethod(env, clazz, "jsPrompt", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;"); 251 m_javaGlue->m_jsUnload = GetJMethod(env, clazz, "jsUnload", "(Ljava/lang/String;Ljava/lang/String;)Z"); 252 m_javaGlue->m_jsInterrupt = GetJMethod(env, clazz, "jsInterrupt", "()Z"); 253 m_javaGlue->m_didFirstLayout = GetJMethod(env, clazz, "didFirstLayout", "(Z)V"); 254 m_javaGlue->m_updateViewport = GetJMethod(env, clazz, "updateViewport", "()V"); 255 m_javaGlue->m_sendNotifyProgressFinished = GetJMethod(env, clazz, "sendNotifyProgressFinished", "()V"); 256 m_javaGlue->m_sendViewInvalidate = GetJMethod(env, clazz, "sendViewInvalidate", "(IIII)V"); 257 m_javaGlue->m_updateTextfield = GetJMethod(env, clazz, "updateTextfield", "(IZLjava/lang/String;I)V"); 258 m_javaGlue->m_updateTextSelection = GetJMethod(env, clazz, "updateTextSelection", "(IIII)V"); 259 m_javaGlue->m_clearTextEntry = GetJMethod(env, clazz, "clearTextEntry", "()V"); 260 m_javaGlue->m_restoreScale = GetJMethod(env, clazz, "restoreScale", "(I)V"); 261 m_javaGlue->m_restoreScreenWidthScale = GetJMethod(env, clazz, "restoreScreenWidthScale", "(I)V"); 262 m_javaGlue->m_needTouchEvents = GetJMethod(env, clazz, "needTouchEvents", "(Z)V"); 263 m_javaGlue->m_requestKeyboard = GetJMethod(env, clazz, "requestKeyboard", "(Z)V"); 264 m_javaGlue->m_exceededDatabaseQuota = GetJMethod(env, clazz, "exceededDatabaseQuota", "(Ljava/lang/String;Ljava/lang/String;JJ)V"); 265 m_javaGlue->m_reachedMaxAppCacheSize = GetJMethod(env, clazz, "reachedMaxAppCacheSize", "(J)V"); 266 m_javaGlue->m_populateVisitedLinks = GetJMethod(env, clazz, "populateVisitedLinks", "()V"); 267 m_javaGlue->m_geolocationPermissionsShowPrompt = GetJMethod(env, clazz, "geolocationPermissionsShowPrompt", "(Ljava/lang/String;)V"); 268 m_javaGlue->m_geolocationPermissionsHidePrompt = GetJMethod(env, clazz, "geolocationPermissionsHidePrompt", "()V"); 269 m_javaGlue->m_addMessageToConsole = GetJMethod(env, clazz, "addMessageToConsole", "(Ljava/lang/String;ILjava/lang/String;)V"); 270 m_javaGlue->m_startFullScreenPluginActivity = GetJMethod(env, clazz, "startFullScreenPluginActivity", "(Ljava/lang/String;Ljava/lang/String;I)V"); 271 m_javaGlue->m_createSurface = GetJMethod(env, clazz, "createSurface", "(Ljava/lang/String;Ljava/lang/String;IIIII)Landroid/webkit/ViewManager$ChildView;"); 272 m_javaGlue->m_updateSurface = GetJMethod(env, clazz, "updateSurface", "(Landroid/webkit/ViewManager$ChildView;IIII)V"); 273 m_javaGlue->m_destroySurface = GetJMethod(env, clazz, "destroySurface", "(Landroid/webkit/ViewManager$ChildView;)V"); 274 m_javaGlue->m_sendFindAgain = GetJMethod(env, clazz, "sendFindAgain", "()V"); 275 276 env->SetIntField(javaWebViewCore, gWebViewCoreFields.m_nativeClass, (jint)this); 277 278 m_scrollOffsetX = m_scrollOffsetY = 0; 279 280 PageGroup::setShouldTrackVisitedLinks(true); 281 282 reset(true); 283} 284 285WebViewCore::~WebViewCore() 286{ 287 // Release the focused view 288 Release(m_popupReply); 289 290 if (m_javaGlue->m_obj) { 291 JNIEnv* env = JSC::Bindings::getJNIEnv(); 292 env->DeleteGlobalRef(m_javaGlue->m_obj); 293 m_javaGlue->m_obj = 0; 294 } 295 delete m_javaGlue; 296 delete m_frameCacheKit; 297 delete m_navPictureKit; 298} 299 300WebViewCore* WebViewCore::getWebViewCore(const WebCore::FrameView* view) 301{ 302 return getWebViewCore(static_cast<const WebCore::ScrollView*>(view)); 303} 304 305WebViewCore* WebViewCore::getWebViewCore(const WebCore::ScrollView* view) 306{ 307 WebFrameView* webFrameView = static_cast<WebFrameView*>(view->platformWidget()); 308 if (!webFrameView) 309 return 0; 310 return webFrameView->webViewCore(); 311} 312 313void WebViewCore::reset(bool fromConstructor) 314{ 315 DBG_SET_LOG(""); 316 if (fromConstructor) { 317 m_frameCacheKit = 0; 318 m_navPictureKit = 0; 319 } else { 320 gFrameCacheMutex.lock(); 321 delete m_frameCacheKit; 322 delete m_navPictureKit; 323 m_frameCacheKit = 0; 324 m_navPictureKit = 0; 325 gFrameCacheMutex.unlock(); 326 } 327 328 m_lastFocused = 0; 329 m_lastFocusedBounds = WebCore::IntRect(0,0,0,0); 330 m_focusBoundsChanged = false; 331 m_lastFocusedSelStart = 0; 332 m_lastFocusedSelEnd = 0; 333 clearContent(); 334 m_updatedFrameCache = true; 335 m_frameCacheOutOfDate = true; 336 m_skipContentDraw = false; 337 m_findIsUp = false; 338 m_domtree_version = 0; 339 m_check_domtree_version = true; 340 m_progressDone = false; 341 m_hasCursorBounds = false; 342 343 m_scrollOffsetX = 0; 344 m_scrollOffsetY = 0; 345 m_screenWidth = 0; 346 m_screenHeight = 0; 347 m_groupForVisitedLinks = NULL; 348} 349 350static bool layoutIfNeededRecursive(WebCore::Frame* f) 351{ 352 if (!f) 353 return true; 354 355 WebCore::FrameView* v = f->view(); 356 if (!v) 357 return true; 358 359 if (v->needsLayout()) 360 v->layout(f->tree()->parent()); 361 362 WebCore::Frame* child = f->tree()->firstChild(); 363 bool success = true; 364 while (child) { 365 success &= layoutIfNeededRecursive(child); 366 child = child->tree()->nextSibling(); 367 } 368 369 return success && !v->needsLayout(); 370} 371 372CacheBuilder& WebViewCore::cacheBuilder() 373{ 374 return FrameLoaderClientAndroid::get(m_mainFrame)->getCacheBuilder(); 375} 376 377WebCore::Node* WebViewCore::currentFocus() 378{ 379 return cacheBuilder().currentFocus(); 380} 381 382void WebViewCore::recordPicture(SkPicture* picture) 383{ 384 // if there is no document yet, just return 385 if (!m_mainFrame->document()) { 386 DBG_NAV_LOG("no document"); 387 return; 388 } 389 // Call layout to ensure that the contentWidth and contentHeight are correct 390 if (!layoutIfNeededRecursive(m_mainFrame)) { 391 DBG_NAV_LOG("layout failed"); 392 return; 393 } 394 // draw into the picture's recording canvas 395 WebCore::FrameView* view = m_mainFrame->view(); 396 DBG_NAV_LOGD("view=(w=%d,h=%d)", view->contentsWidth(), 397 view->contentsHeight()); 398 SkAutoPictureRecord arp(picture, view->contentsWidth(), 399 view->contentsHeight(), PICT_RECORD_FLAGS); 400 SkAutoMemoryUsageProbe mup(__FUNCTION__); 401 402 // Copy m_buttons so we can pass it to our graphics context. 403 gButtonMutex.lock(); 404 WTF::Vector<Container> buttons(m_buttons); 405 gButtonMutex.unlock(); 406 407 WebCore::PlatformGraphicsContext pgc(arp.getRecordingCanvas(), &buttons); 408 WebCore::GraphicsContext gc(&pgc); 409 view->platformWidget()->draw(&gc, WebCore::IntRect(0, 0, INT_MAX, INT_MAX)); 410 411 gButtonMutex.lock(); 412 updateButtonList(&buttons); 413 gButtonMutex.unlock(); 414} 415 416void WebViewCore::recordPictureSet(PictureSet* content) 417{ 418 // if there is no document yet, just return 419 if (!m_mainFrame->document()) { 420 DBG_SET_LOG("!m_mainFrame->document()"); 421 return; 422 } 423 if (m_addInval.isEmpty()) { 424 DBG_SET_LOG("m_addInval.isEmpty()"); 425 return; 426 } 427 // Call layout to ensure that the contentWidth and contentHeight are correct 428 // it's fine for layout to gather invalidates, but defeat sending a message 429 // back to java to call webkitDraw, since we're already in the middle of 430 // doing that 431 m_skipContentDraw = true; 432 bool success = layoutIfNeededRecursive(m_mainFrame); 433 m_skipContentDraw = false; 434 435 // We may be mid-layout and thus cannot draw. 436 if (!success) 437 return; 438 439 { // collect WebViewCoreRecordTimeCounter after layoutIfNeededRecursive 440#ifdef ANDROID_INSTRUMENT 441 TimeCounterAuto counter(TimeCounter::WebViewCoreRecordTimeCounter); 442#endif 443 444 // if the webkit page dimensions changed, discard the pictureset and redraw. 445 WebCore::FrameView* view = m_mainFrame->view(); 446 int width = view->contentsWidth(); 447 int height = view->contentsHeight(); 448 449 // Use the contents width and height as a starting point. 450 SkIRect contentRect; 451 contentRect.set(0, 0, width, height); 452 SkIRect total(contentRect); 453 454 // Traverse all the frames and add their sizes if they are in the visible 455 // rectangle. 456 for (WebCore::Frame* frame = m_mainFrame->tree()->traverseNext(); frame; 457 frame = frame->tree()->traverseNext()) { 458 // If the frame doesn't have an owner then it is the top frame and the 459 // view size is the frame size. 460 WebCore::RenderPart* owner = frame->ownerRenderer(); 461 if (owner && owner->style()->visibility() == VISIBLE) { 462 int x = owner->x(); 463 int y = owner->y(); 464 465 // Traverse the tree up to the parent to find the absolute position 466 // of this frame. 467 WebCore::Frame* parent = frame->tree()->parent(); 468 while (parent) { 469 WebCore::RenderPart* parentOwner = parent->ownerRenderer(); 470 if (parentOwner) { 471 x += parentOwner->x(); 472 y += parentOwner->y(); 473 } 474 parent = parent->tree()->parent(); 475 } 476 // Use the owner dimensions so that padding and border are 477 // included. 478 int right = x + owner->width(); 479 int bottom = y + owner->height(); 480 SkIRect frameRect = {x, y, right, bottom}; 481 // Ignore a width or height that is smaller than 1. Some iframes 482 // have small dimensions in order to be hidden. The iframe 483 // expansion code does not expand in that case so we should ignore 484 // them here. 485 if (frameRect.width() > 1 && frameRect.height() > 1 486 && SkIRect::Intersects(total, frameRect)) 487 total.join(x, y, right, bottom); 488 } 489 } 490 491 // If the new total is larger than the content, resize the view to include 492 // all the content. 493 if (!contentRect.contains(total)) { 494 // Resize the view to change the overflow clip. 495 view->resize(total.fRight, total.fBottom); 496 497 // We have to force a layout in order for the clip to change. 498 m_mainFrame->contentRenderer()->setNeedsLayoutAndPrefWidthsRecalc(); 499 view->forceLayout(); 500 501 // Relayout similar to above 502 m_skipContentDraw = true; 503 bool success = layoutIfNeededRecursive(m_mainFrame); 504 m_skipContentDraw = false; 505 if (!success) 506 return; 507 508 // Set the computed content width 509 width = view->contentsWidth(); 510 height = view->contentsHeight(); 511 } 512 513 content->checkDimensions(width, height, &m_addInval); 514 515 // The inval region may replace existing pictures. The existing pictures 516 // may have already been split into pieces. If reuseSubdivided() returns 517 // true, the split pieces are the last entries in the picture already. They 518 // are marked as invalid, and are rebuilt by rebuildPictureSet(). 519 520 // If the new region doesn't match a set of split pieces, add it to the end. 521 if (!content->reuseSubdivided(m_addInval)) { 522 const SkIRect& inval = m_addInval.getBounds(); 523 SkPicture* picture = rebuildPicture(inval); 524 DBG_SET_LOGD("{%d,%d,w=%d,h=%d}", inval.fLeft, 525 inval.fTop, inval.width(), inval.height()); 526 content->add(m_addInval, picture, 0, false); 527 picture->safeUnref(); 528 } 529 // Remove any pictures already in the set that are obscured by the new one, 530 // and check to see if any already split pieces need to be redrawn. 531 if (content->build()) 532 rebuildPictureSet(content); 533 } // WebViewCoreRecordTimeCounter 534 WebCore::Node* oldFocusNode = currentFocus(); 535 m_frameCacheOutOfDate = true; 536 WebCore::IntRect oldBounds; 537 int oldSelStart = 0; 538 int oldSelEnd = 0; 539 if (oldFocusNode) { 540 oldBounds = oldFocusNode->getRect(); 541 RenderObject* renderer = oldFocusNode->renderer(); 542 if (renderer && (renderer->isTextArea() || renderer->isTextField())) { 543 WebCore::RenderTextControl* rtc = 544 static_cast<WebCore::RenderTextControl*>(renderer); 545 oldSelStart = rtc->selectionStart(); 546 oldSelEnd = rtc->selectionEnd(); 547 } 548 } else 549 oldBounds = WebCore::IntRect(0,0,0,0); 550 unsigned latestVersion = 0; 551 if (m_check_domtree_version) { 552 // as domTreeVersion only increment, we can just check the sum to see 553 // whether we need to update the frame cache 554 for (Frame* frame = m_mainFrame; frame; frame = frame->tree()->traverseNext()) { 555 latestVersion += frame->document()->domTreeVersion(); 556 } 557 } 558 DBG_NAV_LOGD("m_lastFocused=%p oldFocusNode=%p" 559 " m_lastFocusedBounds={%d,%d,%d,%d} oldBounds={%d,%d,%d,%d}" 560 " m_lastFocusedSelection={%d,%d} oldSelection={%d,%d}" 561 " m_check_domtree_version=%s latestVersion=%d m_domtree_version=%d", 562 m_lastFocused, oldFocusNode, 563 m_lastFocusedBounds.x(), m_lastFocusedBounds.y(), 564 m_lastFocusedBounds.width(), m_lastFocusedBounds.height(), 565 oldBounds.x(), oldBounds.y(), oldBounds.width(), oldBounds.height(), 566 m_lastFocusedSelStart, m_lastFocusedSelEnd, oldSelStart, oldSelEnd, 567 m_check_domtree_version ? "true" : "false", 568 latestVersion, m_domtree_version); 569 if (m_lastFocused == oldFocusNode && m_lastFocusedBounds == oldBounds 570 && m_lastFocusedSelStart == oldSelStart 571 && m_lastFocusedSelEnd == oldSelEnd 572 && !m_findIsUp 573 && (!m_check_domtree_version || latestVersion == m_domtree_version)) 574 { 575 return; 576 } 577 m_focusBoundsChanged |= m_lastFocused == oldFocusNode 578 && m_lastFocusedBounds != oldBounds; 579 m_lastFocused = oldFocusNode; 580 m_lastFocusedBounds = oldBounds; 581 m_lastFocusedSelStart = oldSelStart; 582 m_lastFocusedSelEnd = oldSelEnd; 583 m_domtree_version = latestVersion; 584 DBG_NAV_LOG("call updateFrameCache"); 585 updateFrameCache(); 586 if (m_findIsUp) { 587 JNIEnv* env = JSC::Bindings::getJNIEnv(); 588 AutoJObject obj = m_javaGlue->object(env); 589 // if it is called during DESTROY is handled, the real object of WebViewCore 590 // can be gone. Check before using it. 591 if (!obj.get()) 592 return; 593 env->CallVoidMethod(obj.get(), m_javaGlue->m_sendFindAgain); 594 checkException(env); 595 } 596} 597 598void WebViewCore::updateButtonList(WTF::Vector<Container>* buttons) 599{ 600 // All the entries in buttons are either updates of previous entries in 601 // m_buttons or they need to be added to it. 602 Container* end = buttons->end(); 603 for (Container* updatedContainer = buttons->begin(); 604 updatedContainer != end; updatedContainer++) { 605 bool updated = false; 606 // Search for a previous entry that references the same node as our new 607 // data 608 Container* lastPossibleMatch = m_buttons.end(); 609 for (Container* possibleMatch = m_buttons.begin(); 610 possibleMatch != lastPossibleMatch; possibleMatch++) { 611 if (updatedContainer->matches(possibleMatch->node())) { 612 // Update our record, and skip to the next one. 613 possibleMatch->setRect(updatedContainer->rect()); 614 updated = true; 615 break; 616 } 617 } 618 if (!updated) { 619 // This is a brand new button, so append it to m_buttons 620 m_buttons.append(*updatedContainer); 621 } 622 } 623 size_t i = 0; 624 // count will decrease each time one is removed, so check count each time. 625 while (i < m_buttons.size()) { 626 if (m_buttons[i].canBeRemoved()) { 627 m_buttons[i] = m_buttons.last(); 628 m_buttons.removeLast(); 629 } else { 630 i++; 631 } 632 } 633} 634 635void WebViewCore::clearContent() 636{ 637 DBG_SET_LOG(""); 638 m_contentMutex.lock(); 639 m_content.clear(); 640 m_contentMutex.unlock(); 641 m_addInval.setEmpty(); 642 m_rebuildInval.setEmpty(); 643} 644 645void WebViewCore::copyContentToPicture(SkPicture* picture) 646{ 647 DBG_SET_LOG("start"); 648 m_contentMutex.lock(); 649 PictureSet copyContent = PictureSet(m_content); 650 m_contentMutex.unlock(); 651 652 int w = copyContent.width(); 653 int h = copyContent.height(); 654 copyContent.draw(picture->beginRecording(w, h, PICT_RECORD_FLAGS)); 655 picture->endRecording(); 656 DBG_SET_LOG("end"); 657} 658 659bool WebViewCore::drawContent(SkCanvas* canvas, SkColor color) 660{ 661#ifdef ANDROID_INSTRUMENT 662 TimeCounterAuto counter(TimeCounter::WebViewUIDrawTimeCounter); 663#endif 664 DBG_SET_LOG("start"); 665 m_contentMutex.lock(); 666 PictureSet copyContent = PictureSet(m_content); 667 m_contentMutex.unlock(); 668 int sc = canvas->save(SkCanvas::kClip_SaveFlag); 669 SkRect clip; 670 clip.set(0, 0, copyContent.width(), copyContent.height()); 671 canvas->clipRect(clip, SkRegion::kDifference_Op); 672 canvas->drawColor(color); 673 canvas->restoreToCount(sc); 674 bool tookTooLong = copyContent.draw(canvas); 675 m_contentMutex.lock(); 676 m_content.setDrawTimes(copyContent); 677 m_contentMutex.unlock(); 678 DBG_SET_LOG("end"); 679 return tookTooLong; 680} 681 682bool WebViewCore::focusBoundsChanged() 683{ 684 bool result = m_focusBoundsChanged; 685 m_focusBoundsChanged = false; 686 return result; 687} 688 689bool WebViewCore::pictureReady() 690{ 691 bool done; 692 m_contentMutex.lock(); 693 PictureSet copyContent = PictureSet(m_content); 694 done = m_progressDone; 695 m_contentMutex.unlock(); 696 DBG_NAV_LOGD("done=%s empty=%s", done ? "true" : "false", 697 copyContent.isEmpty() ? "true" : "false"); 698 return done || !copyContent.isEmpty(); 699} 700 701SkPicture* WebViewCore::rebuildPicture(const SkIRect& inval) 702{ 703 WebCore::FrameView* view = m_mainFrame->view(); 704 int width = view->contentsWidth(); 705 int height = view->contentsHeight(); 706 SkPicture* picture = new SkPicture(); 707 SkAutoPictureRecord arp(picture, width, height); 708 SkAutoMemoryUsageProbe mup(__FUNCTION__); 709 SkCanvas* recordingCanvas = arp.getRecordingCanvas(); 710 711 gButtonMutex.lock(); 712 WTF::Vector<Container> buttons(m_buttons); 713 gButtonMutex.unlock(); 714 715 WebCore::PlatformGraphicsContext pgc(recordingCanvas, &buttons); 716 WebCore::GraphicsContext gc(&pgc); 717 recordingCanvas->translate(-inval.fLeft, -inval.fTop); 718 recordingCanvas->save(); 719 view->platformWidget()->draw(&gc, WebCore::IntRect(inval.fLeft, 720 inval.fTop, inval.width(), inval.height())); 721 m_rebuildInval.op(inval, SkRegion::kUnion_Op); 722 DBG_SET_LOGD("m_rebuildInval={%d,%d,r=%d,b=%d}", 723 m_rebuildInval.getBounds().fLeft, m_rebuildInval.getBounds().fTop, 724 m_rebuildInval.getBounds().fRight, m_rebuildInval.getBounds().fBottom); 725 726 gButtonMutex.lock(); 727 updateButtonList(&buttons); 728 gButtonMutex.unlock(); 729 730 return picture; 731} 732 733void WebViewCore::rebuildPictureSet(PictureSet* pictureSet) 734{ 735 WebCore::FrameView* view = m_mainFrame->view(); 736 size_t size = pictureSet->size(); 737 for (size_t index = 0; index < size; index++) { 738 if (pictureSet->upToDate(index)) 739 continue; 740 const SkIRect& inval = pictureSet->bounds(index); 741 DBG_SET_LOGD("pictSet=%p [%d] {%d,%d,w=%d,h=%d}", pictureSet, index, 742 inval.fLeft, inval.fTop, inval.width(), inval.height()); 743 pictureSet->setPicture(index, rebuildPicture(inval)); 744 } 745 pictureSet->validate(__FUNCTION__); 746} 747 748bool WebViewCore::recordContent(SkRegion* region, SkIPoint* point) 749{ 750 DBG_SET_LOG("start"); 751 float progress = (float) m_mainFrame->page()->progress()->estimatedProgress(); 752 m_contentMutex.lock(); 753 PictureSet contentCopy(m_content); 754 m_progressDone = progress <= 0.0f || progress >= 1.0f; 755 m_contentMutex.unlock(); 756 recordPictureSet(&contentCopy); 757 if (!m_progressDone && contentCopy.isEmpty()) { 758 DBG_SET_LOGD("empty (progress=%g)", progress); 759 return false; 760 } 761 region->set(m_addInval); 762 m_addInval.setEmpty(); 763 region->op(m_rebuildInval, SkRegion::kUnion_Op); 764 m_rebuildInval.setEmpty(); 765 m_contentMutex.lock(); 766 contentCopy.setDrawTimes(m_content); 767 m_content.set(contentCopy); 768 point->fX = m_content.width(); 769 point->fY = m_content.height(); 770 m_contentMutex.unlock(); 771 DBG_SET_LOGD("region={%d,%d,r=%d,b=%d}", region->getBounds().fLeft, 772 region->getBounds().fTop, region->getBounds().fRight, 773 region->getBounds().fBottom); 774 DBG_SET_LOG("end"); 775 return true; 776} 777 778void WebViewCore::splitContent() 779{ 780 bool layoutSuceeded = layoutIfNeededRecursive(m_mainFrame); 781 LOG_ASSERT(layoutSuceeded, "Can never be called recursively"); 782 PictureSet tempPictureSet; 783 m_contentMutex.lock(); 784 m_content.split(&tempPictureSet); 785 m_contentMutex.unlock(); 786 rebuildPictureSet(&tempPictureSet); 787 m_contentMutex.lock(); 788 m_content.set(tempPictureSet); 789 m_contentMutex.unlock(); 790} 791 792void WebViewCore::scrollTo(int x, int y, bool animate) 793{ 794 LOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!"); 795 796// LOGD("WebViewCore::scrollTo(%d %d)\n", x, y); 797 798 JNIEnv* env = JSC::Bindings::getJNIEnv(); 799 AutoJObject obj = m_javaGlue->object(env); 800 // if it is called during DESTROY is handled, the real object of WebViewCore 801 // can be gone. Check before using it. 802 if (!obj.get()) 803 return; 804 env->CallVoidMethod(obj.get(), animate ? m_javaGlue->m_spawnScrollTo : m_javaGlue->m_scrollTo, x, y); 805 checkException(env); 806} 807 808void WebViewCore::sendNotifyProgressFinished() 809{ 810 LOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!"); 811 JNIEnv* env = JSC::Bindings::getJNIEnv(); 812 AutoJObject obj = m_javaGlue->object(env); 813 // if it is called during DESTROY is handled, the real object of WebViewCore 814 // can be gone. Check before using it. 815 if (!obj.get()) 816 return; 817 env->CallVoidMethod(obj.get(), m_javaGlue->m_sendNotifyProgressFinished); 818 checkException(env); 819} 820 821void WebViewCore::viewInvalidate(const WebCore::IntRect& rect) 822{ 823 LOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!"); 824 JNIEnv* env = JSC::Bindings::getJNIEnv(); 825 AutoJObject obj = m_javaGlue->object(env); 826 // if it is called during DESTROY is handled, the real object of WebViewCore 827 // can be gone. Check before using it. 828 if (!obj.get()) 829 return; 830 env->CallVoidMethod(obj.get(), 831 m_javaGlue->m_sendViewInvalidate, 832 rect.x(), rect.y(), rect.right(), rect.bottom()); 833 checkException(env); 834} 835 836void WebViewCore::scrollBy(int dx, int dy, bool animate) 837{ 838 if (!(dx | dy)) 839 return; 840 JNIEnv* env = JSC::Bindings::getJNIEnv(); 841 AutoJObject obj = m_javaGlue->object(env); 842 // if it is called during DESTROY is handled, the real object of WebViewCore 843 // can be gone. Check before using it. 844 if (!obj.get()) 845 return; 846 env->CallVoidMethod(obj.get(), m_javaGlue->m_scrollBy, 847 dx, dy, animate); 848 checkException(env); 849} 850 851void WebViewCore::contentDraw() 852{ 853 JNIEnv* env = JSC::Bindings::getJNIEnv(); 854 AutoJObject obj = m_javaGlue->object(env); 855 // if it is called during DESTROY is handled, the real object of WebViewCore 856 // can be gone. Check before using it. 857 if (!obj.get()) 858 return; 859 env->CallVoidMethod(obj.get(), m_javaGlue->m_contentDraw); 860 checkException(env); 861} 862 863void WebViewCore::contentInvalidate(const WebCore::IntRect &r) 864{ 865 DBG_SET_LOGD("rect={%d,%d,w=%d,h=%d}", r.x(), r.y(), r.width(), r.height()); 866 SkIRect rect(r); 867 if (!rect.intersect(0, 0, INT_MAX, INT_MAX)) 868 return; 869 m_addInval.op(rect, SkRegion::kUnion_Op); 870 DBG_SET_LOGD("m_addInval={%d,%d,r=%d,b=%d}", 871 m_addInval.getBounds().fLeft, m_addInval.getBounds().fTop, 872 m_addInval.getBounds().fRight, m_addInval.getBounds().fBottom); 873 if (!m_skipContentDraw) 874 contentDraw(); 875} 876 877void WebViewCore::offInvalidate(const WebCore::IntRect &r) 878{ 879 // FIXME: these invalidates are offscreen, and can be throttled or 880 // deferred until the area is visible. For now, treat them as 881 // regular invals so that drawing happens (inefficiently) for now. 882 contentInvalidate(r); 883} 884 885static int pin_pos(int x, int width, int targetWidth) 886{ 887 if (x + width > targetWidth) 888 x = targetWidth - width; 889 if (x < 0) 890 x = 0; 891 return x; 892} 893 894void WebViewCore::didFirstLayout() 895{ 896 DEBUG_NAV_UI_LOGD("%s", __FUNCTION__); 897 LOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!"); 898 899 WebCore::FrameLoader* loader = m_mainFrame->loader(); 900 const WebCore::KURL& url = loader->url(); 901 if (url.isEmpty()) 902 return; 903 LOGV("::WebCore:: didFirstLayout %s", url.string().ascii().data()); 904 905 WebCore::FrameLoadType loadType = loader->loadType(); 906 907 JNIEnv* env = JSC::Bindings::getJNIEnv(); 908 AutoJObject obj = m_javaGlue->object(env); 909 // if it is called during DESTROY is handled, the real object of WebViewCore 910 // can be gone. Check before using it. 911 if (!obj.get()) 912 return; 913 env->CallVoidMethod(obj.get(), m_javaGlue->m_didFirstLayout, 914 loadType == WebCore::FrameLoadTypeStandard 915 // When redirect with locked history, we would like to reset the 916 // scale factor. This is important for www.yahoo.com as it is 917 // redirected to www.yahoo.com/?rs=1 on load. 918 || loadType == WebCore::FrameLoadTypeRedirectWithLockedBackForwardList); 919 checkException(env); 920 DBG_NAV_LOG("call updateFrameCache"); 921 m_check_domtree_version = false; 922 updateFrameCache(); 923 m_history.setDidFirstLayout(true); 924} 925 926void WebViewCore::updateViewport() 927{ 928 DEBUG_NAV_UI_LOGD("%s", __FUNCTION__); 929 LOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!"); 930 931 JNIEnv* env = JSC::Bindings::getJNIEnv(); 932 AutoJObject obj = m_javaGlue->object(env); 933 // if it is called during DESTROY is handled, the real object of WebViewCore 934 // can be gone. Check before using it. 935 if (!obj.get()) 936 return; 937 env->CallVoidMethod(obj.get(), m_javaGlue->m_updateViewport); 938 checkException(env); 939} 940 941void WebViewCore::restoreScale(int scale) 942{ 943 DEBUG_NAV_UI_LOGD("%s", __FUNCTION__); 944 LOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!"); 945 946 JNIEnv* env = JSC::Bindings::getJNIEnv(); 947 AutoJObject obj = m_javaGlue->object(env); 948 // if it is called during DESTROY is handled, the real object of WebViewCore 949 // can be gone. Check before using it. 950 if (!obj.get()) 951 return; 952 env->CallVoidMethod(obj.get(), m_javaGlue->m_restoreScale, scale); 953 checkException(env); 954} 955 956void WebViewCore::restoreScreenWidthScale(int scale) 957{ 958 DEBUG_NAV_UI_LOGD("%s", __FUNCTION__); 959 LOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!"); 960 961 JNIEnv* env = JSC::Bindings::getJNIEnv(); 962 AutoJObject obj = m_javaGlue->object(env); 963 // if it is called during DESTROY is handled, the real object of WebViewCore 964 // can be gone. Check before using it. 965 if (!obj.get()) 966 return; 967 env->CallVoidMethod(obj.get(), m_javaGlue->m_restoreScreenWidthScale, scale); 968 checkException(env); 969} 970 971void WebViewCore::needTouchEvents(bool need) 972{ 973 DEBUG_NAV_UI_LOGD("%s", __FUNCTION__); 974 LOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!"); 975 976#if ENABLE(TOUCH_EVENTS) // Android 977 JNIEnv* env = JSC::Bindings::getJNIEnv(); 978 AutoJObject obj = m_javaGlue->object(env); 979 // if it is called during DESTROY is handled, the real object of WebViewCore 980 // can be gone. Check before using it. 981 if (!obj.get()) 982 return; 983 env->CallVoidMethod(obj.get(), m_javaGlue->m_needTouchEvents, need); 984 checkException(env); 985#endif 986} 987 988void WebViewCore::requestKeyboard(bool showKeyboard) 989{ 990 DBG_NAV_LOGD("showKeyboard=%d", showKeyboard); 991 LOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!"); 992 993 JNIEnv* env = JSC::Bindings::getJNIEnv(); 994 AutoJObject obj = m_javaGlue->object(env); 995 // if it is called during DESTROY is handled, the real object of WebViewCore 996 // can be gone. Check before using it. 997 if (!obj.get()) 998 return; 999 env->CallVoidMethod(obj.get(), m_javaGlue->m_requestKeyboard, showKeyboard); 1000 checkException(env); 1001} 1002 1003void WebViewCore::notifyProgressFinished() 1004{ 1005 DBG_NAV_LOG("call updateFrameCache"); 1006 m_check_domtree_version = true; 1007 updateFrameCache(); 1008 sendNotifyProgressFinished(); 1009} 1010 1011void WebViewCore::doMaxScroll(CacheBuilder::Direction dir) 1012{ 1013 int dx = 0, dy = 0; 1014 1015 switch (dir) { 1016 case CacheBuilder::LEFT: 1017 dx = -m_maxXScroll; 1018 break; 1019 case CacheBuilder::UP: 1020 dy = -m_maxYScroll; 1021 break; 1022 case CacheBuilder::RIGHT: 1023 dx = m_maxXScroll; 1024 break; 1025 case CacheBuilder::DOWN: 1026 dy = m_maxYScroll; 1027 break; 1028 case CacheBuilder::UNINITIALIZED: 1029 default: 1030 LOG_ASSERT(0, "unexpected focus selector"); 1031 } 1032 this->scrollBy(dx, dy, true); 1033} 1034 1035void WebViewCore::setScrollOffset(int moveGeneration, int dx, int dy) 1036{ 1037 DBG_NAV_LOGD("{%d,%d} m_scrollOffset=(%d,%d)", dx, dy, 1038 m_scrollOffsetX, m_scrollOffsetY); 1039 if (m_scrollOffsetX != dx || m_scrollOffsetY != dy) { 1040 m_scrollOffsetX = dx; 1041 m_scrollOffsetY = dy; 1042 // The visible rect is located within our coordinate space so it 1043 // contains the actual scroll position. Setting the location makes hit 1044 // testing work correctly. 1045 m_mainFrame->view()->platformWidget()->setLocation(m_scrollOffsetX, 1046 m_scrollOffsetY); 1047 m_mainFrame->eventHandler()->sendScrollEvent(); 1048 1049 // update the currently visible screen 1050 sendPluginVisibleScreen(); 1051 } 1052 gCursorBoundsMutex.lock(); 1053 bool hasCursorBounds = m_hasCursorBounds; 1054 Frame* frame = (Frame*) m_cursorFrame; 1055 IntPoint location = m_cursorLocation; 1056 gCursorBoundsMutex.unlock(); 1057 if (!hasCursorBounds) 1058 return; 1059 moveMouseIfLatest(moveGeneration, frame, location.x(), location.y()); 1060} 1061 1062void WebViewCore::setGlobalBounds(int x, int y, int h, int v) 1063{ 1064 DBG_NAV_LOGD("{%d,%d}", x, y); 1065 m_mainFrame->view()->platformWidget()->setWindowBounds(x, y, h, v); 1066} 1067 1068void WebViewCore::setSizeScreenWidthAndScale(int width, int height, 1069 int screenWidth, float scale, int realScreenWidth, int screenHeight, 1070 bool ignoreHeight) 1071{ 1072 WebCoreViewBridge* window = m_mainFrame->view()->platformWidget(); 1073 int ow = window->width(); 1074 int oh = window->height(); 1075 window->setSize(width, height); 1076 int osw = m_screenWidth; 1077 DBG_NAV_LOGD("old:(w=%d,h=%d,sw=%d,scale=%g) new:(w=%d,h=%d,sw=%d,scale=%g)", 1078 ow, oh, osw, m_scale, width, height, screenWidth, scale); 1079 m_screenWidth = screenWidth; 1080 m_screenHeight = screenHeight; 1081 if (scale >= 0) { // negative means ignore 1082 m_scale = scale; 1083 if (screenWidth != realScreenWidth) 1084 m_screenWidthScale = realScreenWidth * scale / screenWidth; 1085 else 1086 m_screenWidthScale = m_scale; 1087 } 1088 m_maxXScroll = screenWidth >> 2; 1089 m_maxYScroll = (screenWidth * height / width) >> 2; 1090 if (ow != width || (!ignoreHeight && oh != height) || osw != screenWidth) { 1091 WebCore::RenderObject *r = m_mainFrame->contentRenderer(); 1092 DBG_NAV_LOGD("renderer=%p view=(w=%d,h=%d)", r, 1093 realScreenWidth, screenHeight); 1094 if (r) { 1095 // get current screen center position 1096 WebCore::IntPoint screenCenter = WebCore::IntPoint( 1097 m_scrollOffsetX + (realScreenWidth >> 1), 1098 m_scrollOffsetY + (screenHeight >> 1)); 1099 WebCore::HitTestResult hitTestResult = m_mainFrame->eventHandler()-> 1100 hitTestResultAtPoint(screenCenter, false); 1101 WebCore::Node* node = hitTestResult.innerNode(); 1102 WebCore::IntRect bounds; 1103 WebCore::IntPoint offset; 1104 if (node) { 1105 bounds = node->getRect(); 1106 DBG_NAV_LOGD("ob:(x=%d,y=%d,w=%d,h=%d)", 1107 bounds.x(), bounds.y(), bounds.width(), bounds.height()); 1108 offset = WebCore::IntPoint(screenCenter.x() - bounds.x(), 1109 screenCenter.y() - bounds.y()); 1110 if (offset.x() < 0 || offset.x() > realScreenWidth || 1111 offset.y() < 0 || offset.y() > screenHeight) 1112 { 1113 DBG_NAV_LOGD("offset out of bounds:(x=%d,y=%d)", 1114 offset.x(), offset.y()); 1115 node = 0; 1116 } 1117 } 1118 r->setNeedsLayoutAndPrefWidthsRecalc(); 1119 m_mainFrame->view()->forceLayout(); 1120 // scroll to restore current screen center 1121 if (!node) 1122 return; 1123 const WebCore::IntRect& newBounds = node->getRect(); 1124 DBG_NAV_LOGD("nb:(x=%d,y=%d,w=%d," 1125 "h=%d,ns=%d)", newBounds.x(), newBounds.y(), 1126 newBounds.width(), newBounds.height()); 1127 scrollBy(newBounds.x() - bounds.x(), newBounds.y() - bounds.y(), 1128 false); 1129 } 1130 } 1131 1132 // update the currently visible screen 1133 sendPluginVisibleScreen(); 1134} 1135 1136void WebViewCore::dumpDomTree(bool useFile) 1137{ 1138#ifdef ANDROID_DOM_LOGGING 1139 if (useFile) 1140 gDomTreeFile = fopen(DOM_TREE_LOG_FILE, "w"); 1141 m_mainFrame->document()->showTreeForThis(); 1142 if (gDomTreeFile) { 1143 fclose(gDomTreeFile); 1144 gDomTreeFile = 0; 1145 } 1146#endif 1147} 1148 1149void WebViewCore::dumpRenderTree(bool useFile) 1150{ 1151#ifdef ANDROID_DOM_LOGGING 1152 if (useFile) 1153 gRenderTreeFile = fopen(RENDER_TREE_LOG_FILE, "w"); 1154 WebCore::CString renderDump = WebCore::externalRepresentation(m_mainFrame->contentRenderer()).utf8(); 1155 const char* data = renderDump.data(); 1156 int length = renderDump.length(); 1157 int last = 0; 1158 for (int i = 0; i < length; i++) { 1159 if (data[i] == '\n') { 1160 if (i != last) { 1161 char* chunk = new char[i - last + 1]; 1162 strncpy(chunk, (data + last), i - last); 1163 chunk[i - last] = '\0'; 1164 DUMP_RENDER_LOGD("%s", chunk); 1165 } 1166 last = i + 1; 1167 } 1168 } 1169 if (gRenderTreeFile) { 1170 fclose(gRenderTreeFile); 1171 gRenderTreeFile = 0; 1172 } 1173#endif 1174} 1175 1176void WebViewCore::dumpNavTree() 1177{ 1178#if DUMP_NAV_CACHE 1179 cacheBuilder().mDebug.print(); 1180#endif 1181} 1182 1183WebCore::String WebViewCore::retrieveHref(WebCore::Frame* frame, WebCore::Node* node) 1184{ 1185 if (!CacheBuilder::validNode(m_mainFrame, frame, node)) 1186 return WebCore::String(); 1187 if (!node->hasTagName(WebCore::HTMLNames::aTag)) 1188 return WebCore::String(); 1189 WebCore::HTMLAnchorElement* anchor = static_cast<WebCore::HTMLAnchorElement*>(node); 1190 return anchor->href(); 1191} 1192 1193void WebViewCore::updateCacheOnNodeChange() 1194{ 1195 gCursorBoundsMutex.lock(); 1196 bool hasCursorBounds = m_hasCursorBounds; 1197 Frame* frame = (Frame*) m_cursorFrame; 1198 Node* node = (Node*) m_cursorNode; 1199 IntRect bounds = m_cursorHitBounds; 1200 gCursorBoundsMutex.unlock(); 1201 if (!hasCursorBounds || !node) 1202 return; 1203 if (CacheBuilder::validNode(m_mainFrame, frame, node)) { 1204 RenderObject* renderer = node->renderer(); 1205 if (renderer && renderer->style()->visibility() != HIDDEN) { 1206 IntRect absBox = renderer->absoluteBoundingBoxRect(); 1207 int globalX, globalY; 1208 CacheBuilder::GetGlobalOffset(frame, &globalX, &globalY); 1209 absBox.move(globalX, globalY); 1210 if (absBox == bounds) 1211 return; 1212 DBG_NAV_LOGD("absBox=(%d,%d,%d,%d) bounds=(%d,%d,%d,%d)", 1213 absBox.x(), absBox.y(), absBox.width(), absBox.height(), 1214 bounds.x(), bounds.y(), bounds.width(), bounds.height()); 1215 } 1216 } 1217 DBG_NAV_LOGD("updateFrameCache node=%p", node); 1218 updateFrameCache(); 1219} 1220 1221void WebViewCore::updateFrameCache() 1222{ 1223 if (!m_frameCacheOutOfDate) { 1224 DBG_NAV_LOG("!m_frameCacheOutOfDate"); 1225 return; 1226 } 1227#ifdef ANDROID_INSTRUMENT 1228 TimeCounterAuto counter(TimeCounter::WebViewCoreBuildNavTimeCounter); 1229#endif 1230 m_frameCacheOutOfDate = false; 1231#if DEBUG_NAV_UI 1232 m_now = SkTime::GetMSecs(); 1233#endif 1234 m_temp = new CachedRoot(); 1235 m_temp->init(m_mainFrame, &m_history); 1236 CacheBuilder& builder = cacheBuilder(); 1237 WebCore::Settings* settings = m_mainFrame->page()->settings(); 1238 builder.allowAllTextDetection(); 1239#ifdef ANDROID_META_SUPPORT 1240 if (settings) { 1241 if (!settings->formatDetectionAddress()) 1242 builder.disallowAddressDetection(); 1243 if (!settings->formatDetectionEmail()) 1244 builder.disallowEmailDetection(); 1245 if (!settings->formatDetectionTelephone()) 1246 builder.disallowPhoneDetection(); 1247 } 1248#endif 1249 builder.buildCache(m_temp); 1250 m_tempPict = new SkPicture(); 1251 recordPicture(m_tempPict); 1252 m_temp->setPicture(m_tempPict); 1253 m_temp->setTextGeneration(m_textGeneration); 1254 WebCoreViewBridge* window = m_mainFrame->view()->platformWidget(); 1255 m_temp->setVisibleRect(WebCore::IntRect(m_scrollOffsetX, 1256 m_scrollOffsetY, window->width(), window->height())); 1257 gFrameCacheMutex.lock(); 1258 delete m_frameCacheKit; 1259 delete m_navPictureKit; 1260 m_frameCacheKit = m_temp; 1261 m_navPictureKit = m_tempPict; 1262 m_updatedFrameCache = true; 1263#if DEBUG_NAV_UI 1264 const CachedNode* cachedFocusNode = m_frameCacheKit->currentFocus(); 1265 DBG_NAV_LOGD("cachedFocusNode=%d (nodePointer=%p)", 1266 cachedFocusNode ? cachedFocusNode->index() : 0, 1267 cachedFocusNode ? cachedFocusNode->nodePointer() : 0); 1268#endif 1269 gFrameCacheMutex.unlock(); 1270} 1271 1272void WebViewCore::updateFrameCacheIfLoading() 1273{ 1274 if (!m_check_domtree_version) 1275 updateFrameCache(); 1276} 1277 1278/////////////////////////////////////////////////////////////////////////////// 1279 1280void WebViewCore::addPlugin(PluginWidgetAndroid* w) 1281{ 1282// SkDebugf("----------- addPlugin %p", w); 1283 *m_plugins.append() = w; 1284} 1285 1286void WebViewCore::removePlugin(PluginWidgetAndroid* w) 1287{ 1288// SkDebugf("----------- removePlugin %p", w); 1289 int index = m_plugins.find(w); 1290 if (index < 0) { 1291 SkDebugf("--------------- pluginwindow not found! %p\n", w); 1292 } else { 1293 m_plugins.removeShuffle(index); 1294 } 1295} 1296 1297void WebViewCore::invalPlugin(PluginWidgetAndroid* w) 1298{ 1299 const double PLUGIN_INVAL_DELAY = 1.0 / 60; 1300 1301 if (!m_pluginInvalTimer.isActive()) { 1302 m_pluginInvalTimer.startOneShot(PLUGIN_INVAL_DELAY); 1303 } 1304} 1305 1306void WebViewCore::drawPlugins() 1307{ 1308 SkRegion inval; // accumualte what needs to be redrawn 1309 PluginWidgetAndroid** iter = m_plugins.begin(); 1310 PluginWidgetAndroid** stop = m_plugins.end(); 1311 1312 for (; iter < stop; ++iter) { 1313 PluginWidgetAndroid* w = *iter; 1314 SkIRect dirty; 1315 if (w->isDirty(&dirty)) { 1316 w->draw(); 1317 w->localToDocumentCoords(&dirty); 1318 inval.op(dirty, SkRegion::kUnion_Op); 1319 } 1320 } 1321 1322 if (!inval.isEmpty()) { 1323 // inval.getBounds() is our rectangle 1324 const SkIRect& bounds = inval.getBounds(); 1325 WebCore::IntRect r(bounds.fLeft, bounds.fTop, 1326 bounds.width(), bounds.height()); 1327 this->viewInvalidate(r); 1328 } 1329} 1330 1331void WebViewCore::notifyPluginsOnFrameLoad(const Frame* frame) { 1332 // if frame is the parent then notify all plugins 1333 if (!frame->tree()->parent()) { 1334 // trigger an event notifying the plugins that the page has loaded 1335 ANPEvent event; 1336 SkANP::InitEvent(&event, kLifecycle_ANPEventType); 1337 event.data.lifecycle.action = kOnLoad_ANPLifecycleAction; 1338 sendPluginEvent(event); 1339 } 1340 // else if frame's parent has completed 1341 else if (!frame->tree()->parent()->loader()->isLoading()) { 1342 // send to all plugins who have this frame in their heirarchy 1343 PluginWidgetAndroid** iter = m_plugins.begin(); 1344 PluginWidgetAndroid** stop = m_plugins.end(); 1345 for (; iter < stop; ++iter) { 1346 Frame* currentFrame = (*iter)->pluginView()->parentFrame(); 1347 while (currentFrame) { 1348 if (frame == currentFrame) { 1349 ANPEvent event; 1350 SkANP::InitEvent(&event, kLifecycle_ANPEventType); 1351 event.data.lifecycle.action = kOnLoad_ANPLifecycleAction; 1352 (*iter)->sendEvent(event); 1353 break; 1354 } 1355 currentFrame = currentFrame->tree()->parent(); 1356 } 1357 } 1358 } 1359} 1360 1361void WebViewCore::sendPluginVisibleScreen() 1362{ 1363 ANPRectI visibleRect; 1364 visibleRect.left = m_scrollOffsetX; 1365 visibleRect.top = m_scrollOffsetY; 1366 visibleRect.right = m_scrollOffsetX + m_screenWidth; 1367 visibleRect.bottom = m_scrollOffsetY + m_screenHeight; 1368 1369 PluginWidgetAndroid** iter = m_plugins.begin(); 1370 PluginWidgetAndroid** stop = m_plugins.end(); 1371 for (; iter < stop; ++iter) { 1372 (*iter)->setVisibleScreen(visibleRect, m_scale); 1373 } 1374} 1375 1376void WebViewCore::sendPluginEvent(const ANPEvent& evt, ANPEventFlag flag) 1377{ 1378 PluginWidgetAndroid** iter = m_plugins.begin(); 1379 PluginWidgetAndroid** stop = m_plugins.end(); 1380 for (; iter < stop; ++iter) { 1381 if((*iter)->isAcceptingEvent(flag)) 1382 (*iter)->sendEvent(evt); 1383 } 1384} 1385 1386void WebViewCore::sendPluginEvent(const ANPEvent& evt) 1387{ 1388 PluginWidgetAndroid** iter = m_plugins.begin(); 1389 PluginWidgetAndroid** stop = m_plugins.end(); 1390 for (; iter < stop; ++iter) { 1391 (*iter)->sendEvent(evt); 1392 } 1393} 1394 1395static PluginView* nodeIsPlugin(Node* node) { 1396 RenderObject* renderer = node->renderer(); 1397 if (renderer && renderer->isWidget()) { 1398 Widget* widget = static_cast<RenderWidget*>(renderer)->widget(); 1399 if (widget && widget->isPluginView()) 1400 return static_cast<PluginView*>(widget); 1401 } 1402 return 0; 1403} 1404 1405Node* WebViewCore::cursorNodeIsPlugin() { 1406 gCursorBoundsMutex.lock(); 1407 bool hasCursorBounds = m_hasCursorBounds; 1408 Frame* frame = (Frame*) m_cursorFrame; 1409 Node* node = (Node*) m_cursorNode; 1410 gCursorBoundsMutex.unlock(); 1411 if (hasCursorBounds && CacheBuilder::validNode(m_mainFrame, frame, node) 1412 && nodeIsPlugin(node)) { 1413 return node; 1414 } 1415 return 0; 1416} 1417 1418/////////////////////////////////////////////////////////////////////////////// 1419void WebViewCore::moveMouseIfLatest(int moveGeneration, 1420 WebCore::Frame* frame, int x, int y) 1421{ 1422 DBG_NAV_LOGD("m_moveGeneration=%d moveGeneration=%d" 1423 " frame=%p x=%d y=%d", 1424 m_moveGeneration, moveGeneration, frame, x, y); 1425 if (m_moveGeneration > moveGeneration) { 1426 DBG_NAV_LOGD("m_moveGeneration=%d > moveGeneration=%d", 1427 m_moveGeneration, moveGeneration); 1428 return; // short-circuit if a newer move has already been generated 1429 } 1430 m_lastGeneration = moveGeneration; 1431 moveMouse(frame, x, y); 1432} 1433 1434// Update mouse position and may change focused node. 1435void WebViewCore::moveMouse(WebCore::Frame* frame, int x, int y) 1436{ 1437 DBG_NAV_LOGD("frame=%p x=%d y=%d scrollOffset=(%d,%d)", frame, 1438 x, y, m_scrollOffsetX, m_scrollOffsetY); 1439 if (!frame || CacheBuilder::validNode(m_mainFrame, frame, NULL) == false) 1440 frame = m_mainFrame; 1441 // mouse event expects the position in the window coordinate 1442 m_mousePos = WebCore::IntPoint(x - m_scrollOffsetX, y - m_scrollOffsetY); 1443 // validNode will still return true if the node is null, as long as we have 1444 // a valid frame. Do not want to make a call on frame unless it is valid. 1445 WebCore::PlatformMouseEvent mouseEvent(m_mousePos, m_mousePos, 1446 WebCore::NoButton, WebCore::MouseEventMoved, 1, false, false, false, 1447 false, WTF::currentTime()); 1448 frame->eventHandler()->handleMouseMoveEvent(mouseEvent); 1449 updateCacheOnNodeChange(); 1450} 1451 1452static int findTextBoxIndex(WebCore::Node* node, const WebCore::IntPoint& pt) 1453{ 1454 if (!node->isTextNode()) { 1455 DBG_NAV_LOGD("node=%p pt=(%d,%d) isText=false", node, pt.x(), pt.y()); 1456 return -2; // error 1457 } 1458 WebCore::RenderText* renderText = (WebCore::RenderText*) node->renderer(); 1459 if (!renderText) { 1460 DBG_NAV_LOGD("node=%p pt=(%d,%d) renderText=0", node, pt.x(), pt.y()); 1461 return -3; // error 1462 } 1463 FloatPoint absPt = renderText->localToAbsolute(); 1464 WebCore::InlineTextBox *textBox = renderText->firstTextBox(); 1465 int globalX, globalY; 1466 CacheBuilder::GetGlobalOffset(node, &globalX, &globalY); 1467 int x = pt.x() - globalX; 1468 int y = pt.y() - globalY; 1469 do { 1470 int textBoxStart = textBox->start(); 1471 int textBoxEnd = textBoxStart + textBox->len(); 1472 if (textBoxEnd <= textBoxStart) { 1473 DBG_NAV_LOGD("textBoxStart=%d <= textBoxEnd=%d", textBoxStart, 1474 textBoxEnd); 1475 continue; 1476 } 1477 WebCore::IntRect bounds = textBox->selectionRect(absPt.x(), absPt.y(), 1478 textBoxStart, textBoxEnd); 1479 if (!bounds.contains(x, y)) { 1480 DBG_NAV_LOGD("[absPt=(%g,%g) textBoxStart=%d textBoxEnd=%d]" 1481 " !contains (x=%d, y=%d)", 1482 absPt.x(), absPt.y(), textBoxStart, textBoxEnd, x, y); 1483 continue; 1484 } 1485 int offset = textBox->offsetForPosition(x - absPt.x()); 1486#if DEBUG_NAV_UI 1487 int prior = offset > 0 ? textBox->positionForOffset(offset - 1) : -1; 1488 int current = textBox->positionForOffset(offset); 1489 int next = textBox->positionForOffset(offset + 1); 1490 DBG_NAV_LOGD("offset=%d pt.x=%d globalX=%d renderX=%g x=%d " 1491 "textBox->x()=%d textBox->start()=%d prior=%d current=%d next=%d", 1492 offset, pt.x(), globalX, absPt.x(), x, 1493 textBox->x(), textBox->start(), prior, current, next 1494 ); 1495#endif 1496 return textBox->start() + offset; 1497 } while ((textBox = textBox->nextTextBox())); 1498 return -1; // couldn't find point, may have walked off end 1499} 1500 1501static inline bool isPunctuation(UChar c) 1502{ 1503 return WTF::Unicode::category(c) & (0 1504 | WTF::Unicode::Punctuation_Dash 1505 | WTF::Unicode::Punctuation_Open 1506 | WTF::Unicode::Punctuation_Close 1507 | WTF::Unicode::Punctuation_Connector 1508 | WTF::Unicode::Punctuation_Other 1509 | WTF::Unicode::Punctuation_InitialQuote 1510 | WTF::Unicode::Punctuation_FinalQuote 1511 ); 1512} 1513 1514static int centerX(const SkIRect& rect) 1515{ 1516 return (rect.fLeft + rect.fRight) >> 1; 1517} 1518 1519static int centerY(const SkIRect& rect) 1520{ 1521 return (rect.fTop + rect.fBottom) >> 1; 1522} 1523 1524static void ShowNode(Node* node) 1525{ 1526#if DEBUG_NAV_UI 1527 WebCore::Node* match = node->document(); 1528 int index = 1; 1529 while (match != node && (match = match->traverseNextNode())) 1530 index++; 1531 if (match != node) 1532 index = -1; 1533 const char* name = "text"; 1534 WebCore::CString cstr; 1535 if (!node->isTextNode()) { 1536 cstr = node->localName().string().utf8(); 1537 name = cstr.data(); 1538 } 1539 node->getRect(); 1540 const WebCore::IntRect& b = node->getRect(); 1541 DBG_NAV_LOGD("%s %p (%d) (%d,%d,w=%d,h=%d)", name, node, index, 1542 b.x(), b.y(), b.width(), b.height()); 1543#endif 1544} 1545 1546static WebCore::Node* ChildIsTextNode(WebCore::Node* node) 1547{ 1548 WebCore::Node* child = node; 1549 while (child && !child->isTextNode()) { 1550 ShowNode(child); 1551 child = child->traverseNextNode(node); 1552 } 1553 return child; 1554} 1555 1556WebCore::String WebViewCore::getSelection(SkRegion* selRgn) 1557{ 1558 SkRegion::Iterator iter(*selRgn); 1559 // FIXME: switch this to use StringBuilder instead 1560 WebCore::String result; 1561 WebCore::Node* lastStartNode = 0; 1562 int lastStartEnd = -1; 1563 UChar lastChar = 0xffff; 1564 for (; !iter.done(); iter.next()) { 1565 const SkIRect& rect = iter.rect(); 1566 DBG_NAV_LOGD("rect=(%d, %d, %d, %d)", rect.fLeft, rect.fTop, 1567 rect.fRight, rect.fBottom); 1568 int cy = centerY(rect); 1569 WebCore::IntPoint startPt, endPt; 1570 WebCore::Node* node, * endNode; 1571 for (int top = rect.fTop + 2; top != cy; top = cy) { 1572 startPt = WebCore::IntPoint(rect.fLeft + 1, top); 1573 WebCore::HitTestResult hitTestResult = m_mainFrame->eventHandler()-> 1574 hitTestResultAtPoint(startPt, false); 1575 node = ChildIsTextNode(hitTestResult.innerNode()); 1576 if (node) 1577 break; 1578 DBG_NAV_LOGD("node=%p (%s)", node, top != cy ? "top+1" : "cy"); 1579 } 1580 if (!node) { 1581 DBG_NAV_LOG("!node"); 1582 return result; 1583 } 1584 for (int bottom = rect.fBottom - 1; bottom != cy; bottom = cy) { 1585 for (int right = rect.fRight - 1; right != rect.fRight-2; --right) { 1586 endPt = WebCore::IntPoint(right, bottom); 1587 WebCore::HitTestResult hitTestResult = m_mainFrame-> 1588 eventHandler()->hitTestResultAtPoint(endPt, false); 1589 endNode = ChildIsTextNode(hitTestResult.innerNode()); 1590 if (endNode) 1591 break; 1592 DBG_NAV_LOGD("!endNode=%p (%s) (right-%d)", node, 1593 bottom != cy ? "bottom-1" : "cy", rect.fRight - right); 1594 } 1595 } 1596 if (!endNode) { 1597 DBG_NAV_LOG("!endNode"); 1598 return result; 1599 } 1600 int start = findTextBoxIndex(node, startPt); 1601 if (start < 0) 1602 continue; 1603 int end = findTextBoxIndex(endNode, endPt); 1604 if (end < -1) // use node if endNode is not valid 1605 endNode = node; 1606 if (end <= 0) 1607 end = static_cast<WebCore::Text*>(endNode)->dataImpl()->length(); 1608 DBG_NAV_LOGD("node=%p start=%d endNode=%p end=%d", node, start, endNode, end); 1609 WebCore::Node* startNode = node; 1610 do { 1611 if (!node->isTextNode()) 1612 continue; 1613 if (node->getRect().isEmpty()) 1614 continue; 1615 WebCore::Text* textNode = static_cast<WebCore::Text*>(node); 1616 WebCore::StringImpl* string = textNode->dataImpl(); 1617 if (!string->length()) 1618 continue; 1619 const UChar* chars = string->characters(); 1620 int newLength = node == endNode ? end : string->length(); 1621 if (node == startNode) { 1622 #if DEBUG_NAV_UI 1623 if (node == lastStartNode) 1624 DBG_NAV_LOGD("start=%d last=%d", start, lastStartEnd); 1625 #endif 1626 if (node == lastStartNode && start < lastStartEnd) 1627 break; // skip rect if text overlaps already written text 1628 lastStartNode = node; 1629 lastStartEnd = newLength - start; 1630 } 1631 if (newLength < start) { 1632 DBG_NAV_LOGD("newLen=%d < start=%d", newLength, start); 1633 break; 1634 } 1635 if (!isPunctuation(chars[start])) 1636 result.append(' '); 1637 result.append(chars + start, newLength - start); 1638 start = 0; 1639 } while (node != endNode && (node = node->traverseNextNode())); 1640 } 1641 result = result.simplifyWhiteSpace().stripWhiteSpace(); 1642#if DUMP_NAV_CACHE 1643 { 1644 char buffer[256]; 1645 CacheBuilder::Debug debug; 1646 debug.init(buffer, sizeof(buffer)); 1647 debug.print("copy: "); 1648 debug.wideString(result); 1649 DUMP_NAV_LOGD("%s", buffer); 1650 } 1651#endif 1652 return result; 1653} 1654 1655void WebViewCore::setSelection(int start, int end) 1656{ 1657 WebCore::Node* focus = currentFocus(); 1658 if (!focus) 1659 return; 1660 WebCore::RenderObject* renderer = focus->renderer(); 1661 if (!renderer || (!renderer->isTextField() && !renderer->isTextArea())) 1662 return; 1663 WebCore::RenderTextControl* rtc = static_cast<WebCore::RenderTextControl*>(renderer); 1664 if (start > end) { 1665 int temp = start; 1666 start = end; 1667 end = temp; 1668 } 1669 // Tell our EditorClient that this change was generated from the UI, so it 1670 // does not need to echo it to the UI. 1671 EditorClientAndroid* client = static_cast<EditorClientAndroid*>( 1672 m_mainFrame->editor()->client()); 1673 client->setUiGeneratedSelectionChange(true); 1674 rtc->setSelectionRange(start, end); 1675 client->setUiGeneratedSelectionChange(false); 1676 focus->document()->frame()->revealSelection(); 1677 setFocusControllerActive(true); 1678} 1679 1680void WebViewCore::deleteSelection(int start, int end, int textGeneration) 1681{ 1682 setSelection(start, end); 1683 if (start == end) 1684 return; 1685 WebCore::Node* focus = currentFocus(); 1686 if (!focus) 1687 return; 1688 // Prevent our editor client from passing a message to change the 1689 // selection. 1690 EditorClientAndroid* client = static_cast<EditorClientAndroid*>( 1691 m_mainFrame->editor()->client()); 1692 client->setUiGeneratedSelectionChange(true); 1693 PlatformKeyboardEvent down(kKeyCodeDel, 0, 0, true, false, false, false); 1694 PlatformKeyboardEvent up(kKeyCodeDel, 0, 0, false, false, false, false); 1695 key(down); 1696 key(up); 1697 client->setUiGeneratedSelectionChange(false); 1698 m_textGeneration = textGeneration; 1699} 1700 1701void WebViewCore::replaceTextfieldText(int oldStart, 1702 int oldEnd, const WebCore::String& replace, int start, int end, 1703 int textGeneration) 1704{ 1705 WebCore::Node* focus = currentFocus(); 1706 if (!focus) 1707 return; 1708 setSelection(oldStart, oldEnd); 1709 // Prevent our editor client from passing a message to change the 1710 // selection. 1711 EditorClientAndroid* client = static_cast<EditorClientAndroid*>( 1712 m_mainFrame->editor()->client()); 1713 client->setUiGeneratedSelectionChange(true); 1714 WebCore::TypingCommand::insertText(focus->document(), replace, 1715 false); 1716 client->setUiGeneratedSelectionChange(false); 1717 setSelection(start, end); 1718 m_textGeneration = textGeneration; 1719} 1720 1721void WebViewCore::passToJs(int generation, const WebCore::String& current, 1722 const PlatformKeyboardEvent& event) 1723{ 1724 WebCore::Node* focus = currentFocus(); 1725 if (!focus) { 1726 DBG_NAV_LOG("!focus"); 1727 clearTextEntry(); 1728 return; 1729 } 1730 WebCore::RenderObject* renderer = focus->renderer(); 1731 if (!renderer || (!renderer->isTextField() && !renderer->isTextArea())) { 1732 DBG_NAV_LOGD("renderer==%p || not text", renderer); 1733 clearTextEntry(); 1734 return; 1735 } 1736 // Block text field updates during a key press. 1737 m_blockTextfieldUpdates = true; 1738 // Also prevent our editor client from passing a message to change the 1739 // selection. 1740 EditorClientAndroid* client = static_cast<EditorClientAndroid*>( 1741 m_mainFrame->editor()->client()); 1742 client->setUiGeneratedSelectionChange(true); 1743 key(event); 1744 client->setUiGeneratedSelectionChange(false); 1745 m_blockTextfieldUpdates = false; 1746 m_textGeneration = generation; 1747 setFocusControllerActive(true); 1748 WebCore::RenderTextControl* renderText = 1749 static_cast<WebCore::RenderTextControl*>(renderer); 1750 WebCore::String test = renderText->text(); 1751 if (test == current) { 1752 DBG_NAV_LOG("test == current"); 1753 return; 1754 } 1755 // If the text changed during the key event, update the UI text field. 1756 updateTextfield(focus, false, test); 1757} 1758 1759void WebViewCore::scrollFocusedTextInput(float xPercent, int y) 1760{ 1761 WebCore::Node* focus = currentFocus(); 1762 if (!focus) { 1763 DBG_NAV_LOG("!focus"); 1764 clearTextEntry(); 1765 return; 1766 } 1767 WebCore::RenderObject* renderer = focus->renderer(); 1768 if (!renderer || (!renderer->isTextField() && !renderer->isTextArea())) { 1769 DBG_NAV_LOGD("renderer==%p || not text", renderer); 1770 clearTextEntry(); 1771 return; 1772 } 1773 WebCore::RenderTextControl* renderText = 1774 static_cast<WebCore::RenderTextControl*>(renderer); 1775 int x = (int) (xPercent * (renderText->scrollWidth() - 1776 renderText->clientWidth())); 1777 DBG_NAV_LOGD("x=%d y=%d xPercent=%g scrollW=%d clientW=%d", x, y, 1778 xPercent, renderText->scrollWidth(), renderText->clientWidth()); 1779 renderText->setScrollLeft(x); 1780 renderText->setScrollTop(y); 1781} 1782 1783void WebViewCore::setFocusControllerActive(bool active) 1784{ 1785 m_mainFrame->page()->focusController()->setActive(active); 1786} 1787 1788void WebViewCore::saveDocumentState(WebCore::Frame* frame) 1789{ 1790 if (!CacheBuilder::validNode(m_mainFrame, frame, 0)) 1791 frame = m_mainFrame; 1792 WebCore::HistoryItem *item = frame->loader()->currentHistoryItem(); 1793 1794 // item can be null when there is no offical URL for the current page. This happens 1795 // when the content is loaded using with WebCoreFrameBridge::LoadData() and there 1796 // is no failing URL (common case is when content is loaded using data: scheme) 1797 if (item) { 1798 item->setDocumentState(frame->document()->formElementsState()); 1799 } 1800} 1801 1802// Convert a WebCore::String into an array of characters where the first 1803// character represents the length, for easy conversion to java. 1804static uint16_t* stringConverter(const WebCore::String& text) 1805{ 1806 size_t length = text.length(); 1807 uint16_t* itemName = new uint16_t[length+1]; 1808 itemName[0] = (uint16_t)length; 1809 uint16_t* firstChar = &(itemName[1]); 1810 memcpy((void*)firstChar, text.characters(), sizeof(UChar)*length); 1811 return itemName; 1812} 1813 1814// Response to dropdown created for a listbox. 1815class ListBoxReply : public WebCoreReply { 1816public: 1817 ListBoxReply(WebCore::HTMLSelectElement* select, WebCore::Frame* frame, WebViewCore* view) 1818 : m_select(select) 1819 , m_frame(frame) 1820 , m_viewImpl(view) 1821 {} 1822 1823 // Response used if the listbox only allows single selection. 1824 // index is listIndex of the selected item, or -1 if nothing is selected. 1825 virtual void replyInt(int index) 1826 { 1827 if (-2 == index) { 1828 // Special value for cancel. Do nothing. 1829 return; 1830 } 1831 // If the select element no longer exists, due to a page change, etc, 1832 // silently return. 1833 if (!m_select || !CacheBuilder::validNode(m_viewImpl->m_mainFrame, 1834 m_frame, m_select)) 1835 return; 1836 // Use a pointer to HTMLSelectElement's superclass, where 1837 // listToOptionIndex is public. 1838 SelectElement* selectElement = m_select; 1839 int optionIndex = selectElement->listToOptionIndex(index); 1840 m_select->setSelectedIndex(optionIndex, true); 1841 m_select->dispatchFormControlChangeEvent(); 1842 m_viewImpl->contentInvalidate(m_select->getRect()); 1843 } 1844 1845 // Response if the listbox allows multiple selection. array stores the listIndices 1846 // of selected positions. 1847 virtual void replyIntArray(const int* array, int count) 1848 { 1849 // If the select element no longer exists, due to a page change, etc, 1850 // silently return. 1851 if (!m_select || !CacheBuilder::validNode(m_viewImpl->m_mainFrame, 1852 m_frame, m_select)) 1853 return; 1854 1855 // If count is 1 or 0, use replyInt. 1856 SkASSERT(count > 1); 1857 1858 const WTF::Vector<Element*>& items = m_select->listItems(); 1859 int totalItems = static_cast<int>(items.size()); 1860 // Keep track of the position of the value we are comparing against. 1861 int arrayIndex = 0; 1862 // The value we are comparing against. 1863 int selection = array[arrayIndex]; 1864 WebCore::HTMLOptionElement* option; 1865 for (int listIndex = 0; listIndex < totalItems; listIndex++) { 1866 if (items[listIndex]->hasLocalName(WebCore::HTMLNames::optionTag)) { 1867 option = static_cast<WebCore::HTMLOptionElement*>( 1868 items[listIndex]); 1869 if (listIndex == selection) { 1870 option->setSelectedState(true); 1871 arrayIndex++; 1872 if (arrayIndex == count) 1873 selection = -1; 1874 else 1875 selection = array[arrayIndex]; 1876 } else 1877 option->setSelectedState(false); 1878 } 1879 } 1880 m_select->dispatchFormControlChangeEvent(); 1881 m_viewImpl->contentInvalidate(m_select->getRect()); 1882 } 1883private: 1884 // The select element associated with this listbox. 1885 WebCore::HTMLSelectElement* m_select; 1886 // The frame of this select element, to verify that it is valid. 1887 WebCore::Frame* m_frame; 1888 // For calling invalidate and checking the select element's validity 1889 WebViewCore* m_viewImpl; 1890}; 1891 1892// Create an array of java Strings. 1893static jobjectArray makeLabelArray(JNIEnv* env, const uint16_t** labels, size_t count) 1894{ 1895 jclass stringClass = env->FindClass("java/lang/String"); 1896 LOG_ASSERT(stringClass, "Could not find java/lang/String"); 1897 jobjectArray array = env->NewObjectArray(count, stringClass, 0); 1898 LOG_ASSERT(array, "Could not create new string array"); 1899 1900 for (size_t i = 0; i < count; i++) { 1901 jobject newString = env->NewString(&labels[i][1], labels[i][0]); 1902 env->SetObjectArrayElement(array, i, newString); 1903 env->DeleteLocalRef(newString); 1904 checkException(env); 1905 } 1906 env->DeleteLocalRef(stringClass); 1907 return array; 1908} 1909 1910void WebViewCore::openFileChooser(PassRefPtr<WebCore::FileChooser> chooser) { 1911 if (!chooser) 1912 return; 1913 JNIEnv* env = JSC::Bindings::getJNIEnv(); 1914 jstring jName = (jstring) env->CallObjectMethod( 1915 m_javaGlue->object(env).get(), m_javaGlue->m_openFileChooser); 1916 checkException(env); 1917 const UChar* string = (const UChar*) env->GetStringChars(jName, NULL); 1918 if (!string) 1919 return; 1920 WebCore::String webcoreString = to_string(env, jName); 1921 env->ReleaseStringChars(jName, string); 1922 chooser->chooseFile(webcoreString); 1923} 1924 1925void WebViewCore::listBoxRequest(WebCoreReply* reply, const uint16_t** labels, size_t count, const int enabled[], size_t enabledCount, 1926 bool multiple, const int selected[], size_t selectedCountOrSelection) 1927{ 1928 // If m_popupReply is not null, then we already have a list showing. 1929 if (m_popupReply != 0) 1930 return; 1931 1932 LOG_ASSERT(m_javaGlue->m_obj, "No java widget associated with this view!"); 1933 1934 // Create an array of java Strings for the drop down. 1935 JNIEnv* env = JSC::Bindings::getJNIEnv(); 1936 AutoJObject obj = m_javaGlue->object(env); 1937 // if it is called during DESTROY is handled, the real object of WebViewCore 1938 // can be gone. Check before using it. 1939 if (!obj.get()) 1940 return; 1941 jobjectArray labelArray = makeLabelArray(env, labels, count); 1942 1943 // Create an array determining whether each item is enabled. 1944 jintArray enabledArray = env->NewIntArray(enabledCount); 1945 checkException(env); 1946 jint* ptrArray = env->GetIntArrayElements(enabledArray, 0); 1947 checkException(env); 1948 for (size_t i = 0; i < enabledCount; i++) { 1949 ptrArray[i] = enabled[i]; 1950 } 1951 env->ReleaseIntArrayElements(enabledArray, ptrArray, 0); 1952 checkException(env); 1953 1954 if (multiple) { 1955 // Pass up an array representing which items are selected. 1956 jintArray selectedArray = env->NewIntArray(selectedCountOrSelection); 1957 checkException(env); 1958 jint* selArray = env->GetIntArrayElements(selectedArray, 0); 1959 checkException(env); 1960 for (size_t i = 0; i < selectedCountOrSelection; i++) { 1961 selArray[i] = selected[i]; 1962 } 1963 env->ReleaseIntArrayElements(selectedArray, selArray, 0); 1964 1965 env->CallVoidMethod(obj.get(), m_javaGlue->m_requestListBox, labelArray, enabledArray, selectedArray); 1966 env->DeleteLocalRef(selectedArray); 1967 } else { 1968 // Pass up the single selection. 1969 env->CallVoidMethod(obj.get(), m_javaGlue->m_requestSingleListBox, labelArray, enabledArray, selectedCountOrSelection); 1970 } 1971 1972 env->DeleteLocalRef(labelArray); 1973 env->DeleteLocalRef(enabledArray); 1974 checkException(env); 1975 1976 Retain(reply); 1977 m_popupReply = reply; 1978} 1979 1980bool WebViewCore::key(const PlatformKeyboardEvent& event) 1981{ 1982 WebCore::EventHandler* eventHandler = m_mainFrame->eventHandler(); 1983 WebCore::Node* focusNode = currentFocus(); 1984 if (focusNode) 1985 eventHandler = focusNode->document()->frame()->eventHandler(); 1986 DBG_NAV_LOGD("keyCode=%s unichar=%d focusNode=%p", 1987 event.keyIdentifier().utf8().data(), event.unichar(), focusNode); 1988 return eventHandler->keyEvent(event); 1989} 1990 1991// For when the user clicks the trackball 1992void WebViewCore::click(WebCore::Frame* frame, WebCore::Node* node) { 1993 if (!node) { 1994 WebCore::IntPoint pt = m_mousePos; 1995 pt.move(m_scrollOffsetX, m_scrollOffsetY); 1996 WebCore::HitTestResult hitTestResult = m_mainFrame->eventHandler()-> 1997 hitTestResultAtPoint(pt, false); 1998 node = hitTestResult.innerNode(); 1999 frame = node->document()->frame(); 2000 DBG_NAV_LOGD("m_mousePos=(%d,%d) m_scrollOffset=(%d,%d) pt=(%d,%d)" 2001 " node=%p", m_mousePos.x(), m_mousePos.y(), 2002 m_scrollOffsetX, m_scrollOffsetY, pt.x(), pt.y(), node); 2003 } 2004 if (node) { 2005 EditorClientAndroid* client 2006 = static_cast<EditorClientAndroid*>( 2007 m_mainFrame->editor()->client()); 2008 client->setShouldChangeSelectedRange(false); 2009 handleMouseClick(frame, node); 2010 client->setShouldChangeSelectedRange(true); 2011 } 2012} 2013 2014bool WebViewCore::handleTouchEvent(int action, int x, int y) 2015{ 2016 bool preventDefault = false; 2017 2018#if ENABLE(TOUCH_EVENTS) // Android 2019 WebCore::TouchEventType type = WebCore::TouchEventCancel; 2020 switch (action) { 2021 case 0: // MotionEvent.ACTION_DOWN 2022 type = WebCore::TouchEventStart; 2023 break; 2024 case 1: // MotionEvent.ACTION_UP 2025 type = WebCore::TouchEventEnd; 2026 break; 2027 case 2: // MotionEvent.ACTION_MOVE 2028 type = WebCore::TouchEventMove; 2029 break; 2030 case 3: // MotionEvent.ACTION_CANCEL 2031 type = WebCore::TouchEventCancel; 2032 break; 2033 } 2034 WebCore::IntPoint pt(x - m_scrollOffsetX, y - m_scrollOffsetY); 2035 WebCore::PlatformTouchEvent te(pt, pt, type); 2036 preventDefault = m_mainFrame->eventHandler()->handleTouchEvent(te); 2037#endif 2038 2039 return preventDefault; 2040} 2041 2042void WebViewCore::touchUp(int touchGeneration, 2043 WebCore::Frame* frame, WebCore::Node* node, int x, int y) 2044{ 2045 if (m_touchGeneration > touchGeneration) { 2046 DBG_NAV_LOGD("m_touchGeneration=%d > touchGeneration=%d" 2047 " x=%d y=%d", m_touchGeneration, touchGeneration, x, y); 2048 return; // short circuit if a newer touch has been generated 2049 } 2050 // This moves m_mousePos to the correct place, and handleMouseClick uses 2051 // m_mousePos to determine where the click happens. 2052 moveMouse(frame, x, y); 2053 m_lastGeneration = touchGeneration; 2054 if (frame && CacheBuilder::validNode(m_mainFrame, frame, 0)) { 2055 frame->loader()->resetMultipleFormSubmissionProtection(); 2056 } 2057 DBG_NAV_LOGD("touchGeneration=%d handleMouseClick frame=%p node=%p" 2058 " x=%d y=%d", touchGeneration, frame, node, x, y); 2059 handleMouseClick(frame, node); 2060} 2061 2062// Common code for both clicking with the trackball and touchUp 2063bool WebViewCore::handleMouseClick(WebCore::Frame* framePtr, WebCore::Node* nodePtr) 2064{ 2065 bool valid = framePtr == NULL 2066 || CacheBuilder::validNode(m_mainFrame, framePtr, nodePtr); 2067 WebFrame* webFrame = WebFrame::getWebFrame(m_mainFrame); 2068 if (valid && nodePtr) { 2069 // Need to special case area tags because an image map could have an area element in the middle 2070 // so when attempting to get the default, the point chosen would be follow the wrong link. 2071 if (nodePtr->hasTagName(WebCore::HTMLNames::areaTag)) { 2072 webFrame->setUserInitiatedClick(true); 2073 nodePtr->dispatchSimulatedClick(0, true, true); 2074 webFrame->setUserInitiatedClick(false); 2075 DBG_NAV_LOG("area"); 2076 return true; 2077 } 2078 WebCore::RenderObject* renderer = nodePtr->renderer(); 2079 if (renderer && (renderer->isMenuList() || renderer->isListBox())) { 2080 WebCore::HTMLSelectElement* select = static_cast<WebCore::HTMLSelectElement*>(nodePtr); 2081 const WTF::Vector<WebCore::Element*>& listItems = select->listItems(); 2082 SkTDArray<const uint16_t*> names; 2083 // Possible values for enabledArray. Keep in Sync with values in 2084 // InvokeListBox.Container in WebView.java 2085 enum OptionStatus { 2086 OPTGROUP = -1, 2087 OPTION_DISABLED = 0, 2088 OPTION_ENABLED = 1, 2089 }; 2090 SkTDArray<int> enabledArray; 2091 SkTDArray<int> selectedArray; 2092 int size = listItems.size(); 2093 bool multiple = select->multiple(); 2094 for (int i = 0; i < size; i++) { 2095 if (listItems[i]->hasTagName(WebCore::HTMLNames::optionTag)) { 2096 WebCore::HTMLOptionElement* option = static_cast<WebCore::HTMLOptionElement*>(listItems[i]); 2097 *names.append() = stringConverter(option->textIndentedToRespectGroupLabel()); 2098 *enabledArray.append() = option->disabled() ? OPTION_DISABLED : OPTION_ENABLED; 2099 if (multiple && option->selected()) 2100 *selectedArray.append() = i; 2101 } else if (listItems[i]->hasTagName(WebCore::HTMLNames::optgroupTag)) { 2102 WebCore::HTMLOptGroupElement* optGroup = static_cast<WebCore::HTMLOptGroupElement*>(listItems[i]); 2103 *names.append() = stringConverter(optGroup->groupLabelText()); 2104 *enabledArray.append() = OPTGROUP; 2105 } 2106 } 2107 WebCoreReply* reply = new ListBoxReply(select, select->document()->frame(), this); 2108 // Use a pointer to HTMLSelectElement's superclass, where 2109 // optionToListIndex is public. 2110 SelectElement* selectElement = select; 2111 listBoxRequest(reply, names.begin(), size, enabledArray.begin(), enabledArray.count(), 2112 multiple, selectedArray.begin(), multiple ? selectedArray.count() : 2113 selectElement->optionToListIndex(select->selectedIndex())); 2114 DBG_NAV_LOG("menu list"); 2115 return true; 2116 } 2117 } 2118 if (!valid || !framePtr) 2119 framePtr = m_mainFrame; 2120 webFrame->setUserInitiatedClick(true); 2121 WebCore::PlatformMouseEvent mouseDown(m_mousePos, m_mousePos, WebCore::LeftButton, 2122 WebCore::MouseEventPressed, 1, false, false, false, false, 2123 WTF::currentTime()); 2124 // ignore the return from as it will return true if the hit point can trigger selection change 2125 framePtr->eventHandler()->handleMousePressEvent(mouseDown); 2126 WebCore::PlatformMouseEvent mouseUp(m_mousePos, m_mousePos, WebCore::LeftButton, 2127 WebCore::MouseEventReleased, 1, false, false, false, false, 2128 WTF::currentTime()); 2129 bool handled = framePtr->eventHandler()->handleMouseReleaseEvent(mouseUp); 2130 webFrame->setUserInitiatedClick(false); 2131 2132 // If the user clicked on a textfield, make the focusController active 2133 // so we show the blinking cursor. 2134 WebCore::Node* focusNode = currentFocus(); 2135 DBG_NAV_LOGD("m_mousePos={%d,%d} focusNode=%p handled=%s", m_mousePos.x(), 2136 m_mousePos.y(), focusNode, handled ? "true" : "false"); 2137 if (focusNode) { 2138 WebCore::RenderObject* renderer = focusNode->renderer(); 2139 if (renderer && (renderer->isTextField() || renderer->isTextArea())) 2140 setFocusControllerActive(true); 2141 } 2142 return handled; 2143} 2144 2145void WebViewCore::popupReply(int index) 2146{ 2147 if (m_popupReply) { 2148 m_popupReply->replyInt(index); 2149 Release(m_popupReply); 2150 m_popupReply = 0; 2151 } 2152} 2153 2154void WebViewCore::popupReply(const int* array, int count) 2155{ 2156 if (m_popupReply) { 2157 m_popupReply->replyIntArray(array, count); 2158 Release(m_popupReply); 2159 m_popupReply = NULL; 2160 } 2161} 2162 2163void WebViewCore::addMessageToConsole(const WebCore::String& message, unsigned int lineNumber, const WebCore::String& sourceID) { 2164 JNIEnv* env = JSC::Bindings::getJNIEnv(); 2165 AutoJObject obj = m_javaGlue->object(env); 2166 // if it is called during DESTROY is handled, the real object of WebViewCore 2167 // can be gone. Check before using it. 2168 if (!obj.get()) 2169 return; 2170 jstring jMessageStr = env->NewString((unsigned short *)message.characters(), message.length()); 2171 jstring jSourceIDStr = env->NewString((unsigned short *)sourceID.characters(), sourceID.length()); 2172 env->CallVoidMethod(obj.get(), m_javaGlue->m_addMessageToConsole, jMessageStr, lineNumber, jSourceIDStr); 2173 env->DeleteLocalRef(jMessageStr); 2174 env->DeleteLocalRef(jSourceIDStr); 2175 checkException(env); 2176} 2177 2178void WebViewCore::jsAlert(const WebCore::String& url, const WebCore::String& text) 2179{ 2180 JNIEnv* env = JSC::Bindings::getJNIEnv(); 2181 AutoJObject obj = m_javaGlue->object(env); 2182 // if it is called during DESTROY is handled, the real object of WebViewCore 2183 // can be gone. Check before using it. 2184 if (!obj.get()) 2185 return; 2186 jstring jInputStr = env->NewString((unsigned short *)text.characters(), text.length()); 2187 jstring jUrlStr = env->NewString((unsigned short *)url.characters(), url.length()); 2188 env->CallVoidMethod(obj.get(), m_javaGlue->m_jsAlert, jUrlStr, jInputStr); 2189 env->DeleteLocalRef(jInputStr); 2190 env->DeleteLocalRef(jUrlStr); 2191 checkException(env); 2192} 2193 2194void WebViewCore::exceededDatabaseQuota(const WebCore::String& url, const WebCore::String& databaseIdentifier, const unsigned long long currentQuota, unsigned long long estimatedSize) 2195{ 2196#if ENABLE(DATABASE) 2197 JNIEnv* env = JSC::Bindings::getJNIEnv(); 2198 AutoJObject obj = m_javaGlue->object(env); 2199 // if it is called during DESTROY is handled, the real object of WebViewCore 2200 // can be gone. Check before using it. 2201 if (!obj.get()) 2202 return; 2203 jstring jDatabaseIdentifierStr = env->NewString((unsigned short *)databaseIdentifier.characters(), databaseIdentifier.length()); 2204 jstring jUrlStr = env->NewString((unsigned short *)url.characters(), url.length()); 2205 env->CallVoidMethod(obj.get(), m_javaGlue->m_exceededDatabaseQuota, jUrlStr, jDatabaseIdentifierStr, currentQuota, estimatedSize); 2206 env->DeleteLocalRef(jDatabaseIdentifierStr); 2207 env->DeleteLocalRef(jUrlStr); 2208 checkException(env); 2209#endif 2210} 2211 2212void WebViewCore::reachedMaxAppCacheSize(const unsigned long long spaceNeeded) 2213{ 2214#if ENABLE(OFFLINE_WEB_APPLICATIONS) 2215 JNIEnv* env = JSC::Bindings::getJNIEnv(); 2216 AutoJObject obj = m_javaGlue->object(env); 2217 // if it is called during DESTROY is handled, the real object of WebViewCore 2218 // can be gone. Check before using it. 2219 if (!obj.get()) 2220 return; 2221 env->CallVoidMethod(obj.get(), m_javaGlue->m_reachedMaxAppCacheSize, spaceNeeded); 2222 checkException(env); 2223#endif 2224} 2225 2226void WebViewCore::populateVisitedLinks(WebCore::PageGroup* group) 2227{ 2228 m_groupForVisitedLinks = group; 2229 JNIEnv* env = JSC::Bindings::getJNIEnv(); 2230 AutoJObject obj = m_javaGlue->object(env); 2231 // if it is called during DESTROY is handled, the real object of WebViewCore 2232 // can be gone. Check before using it. 2233 if (!obj.get()) 2234 return; 2235 env->CallVoidMethod(obj.get(), m_javaGlue->m_populateVisitedLinks); 2236 checkException(env); 2237} 2238 2239void WebViewCore::geolocationPermissionsShowPrompt(const WebCore::String& origin) 2240{ 2241 JNIEnv* env = JSC::Bindings::getJNIEnv(); 2242 AutoJObject obj = m_javaGlue->object(env); 2243 // if it is called during DESTROY is handled, the real object of WebViewCore 2244 // can be gone. Check before using it. 2245 if (!obj.get()) 2246 return; 2247 jstring originString = env->NewString((unsigned short *)origin.characters(), origin.length()); 2248 env->CallVoidMethod(obj.get(), 2249 m_javaGlue->m_geolocationPermissionsShowPrompt, 2250 originString); 2251 env->DeleteLocalRef(originString); 2252 checkException(env); 2253} 2254 2255void WebViewCore::geolocationPermissionsHidePrompt() 2256{ 2257 JNIEnv* env = JSC::Bindings::getJNIEnv(); 2258 AutoJObject obj = m_javaGlue->object(env); 2259 // if it is called during DESTROY is handled, the real object of WebViewCore 2260 // can be gone. Check before using it. 2261 if (!obj.get()) 2262 return; 2263 env->CallVoidMethod(obj.get(), 2264 m_javaGlue->m_geolocationPermissionsHidePrompt); 2265 checkException(env); 2266} 2267 2268bool WebViewCore::jsConfirm(const WebCore::String& url, const WebCore::String& text) 2269{ 2270 JNIEnv* env = JSC::Bindings::getJNIEnv(); 2271 AutoJObject obj = m_javaGlue->object(env); 2272 // if it is called during DESTROY is handled, the real object of WebViewCore 2273 // can be gone. Check before using it. 2274 if (!obj.get()) 2275 return false; 2276 jstring jInputStr = env->NewString((unsigned short *)text.characters(), text.length()); 2277 jstring jUrlStr = env->NewString((unsigned short *)url.characters(), url.length()); 2278 jboolean result = env->CallBooleanMethod(obj.get(), m_javaGlue->m_jsConfirm, jUrlStr, jInputStr); 2279 env->DeleteLocalRef(jInputStr); 2280 env->DeleteLocalRef(jUrlStr); 2281 checkException(env); 2282 return result; 2283} 2284 2285bool WebViewCore::jsPrompt(const WebCore::String& url, const WebCore::String& text, const WebCore::String& defaultValue, WebCore::String& result) 2286{ 2287 JNIEnv* env = JSC::Bindings::getJNIEnv(); 2288 AutoJObject obj = m_javaGlue->object(env); 2289 // if it is called during DESTROY is handled, the real object of WebViewCore 2290 // can be gone. Check before using it. 2291 if (!obj.get()) 2292 return false; 2293 2294 jstring jInputStr = env->NewString((unsigned short *)text.characters(), text.length()); 2295 jstring jDefaultStr = env->NewString((unsigned short *)defaultValue.characters(), defaultValue.length()); 2296 jstring jUrlStr = env->NewString((unsigned short *)url.characters(), url.length()); 2297 jstring returnVal = (jstring) env->CallObjectMethod(obj.get(), m_javaGlue->m_jsPrompt, jUrlStr, jInputStr, jDefaultStr); 2298 // If returnVal is null, it means that the user cancelled the dialog. 2299 if (!returnVal) 2300 return false; 2301 2302 result = to_string(env, returnVal); 2303 env->DeleteLocalRef(jInputStr); 2304 env->DeleteLocalRef(jDefaultStr); 2305 env->DeleteLocalRef(jUrlStr); 2306 checkException(env); 2307 return true; 2308} 2309 2310bool WebViewCore::jsUnload(const WebCore::String& url, const WebCore::String& message) 2311{ 2312 JNIEnv* env = JSC::Bindings::getJNIEnv(); 2313 AutoJObject obj = m_javaGlue->object(env); 2314 // if it is called during DESTROY is handled, the real object of WebViewCore 2315 // can be gone. Check before using it. 2316 if (!obj.get()) 2317 return false; 2318 jstring jInputStr = env->NewString((unsigned short *)message.characters(), message.length()); 2319 jstring jUrlStr = env->NewString((unsigned short *)url.characters(), url.length()); 2320 jboolean result = env->CallBooleanMethod(obj.get(), m_javaGlue->m_jsUnload, jUrlStr, jInputStr); 2321 env->DeleteLocalRef(jInputStr); 2322 env->DeleteLocalRef(jUrlStr); 2323 checkException(env); 2324 return result; 2325} 2326 2327bool WebViewCore::jsInterrupt() 2328{ 2329 JNIEnv* env = JSC::Bindings::getJNIEnv(); 2330 AutoJObject obj = m_javaGlue->object(env); 2331 // if it is called during DESTROY is handled, the real object of WebViewCore 2332 // can be gone. Check before using it. 2333 if (!obj.get()) 2334 return true; // default to interrupt 2335 jboolean result = env->CallBooleanMethod(obj.get(), m_javaGlue->m_jsInterrupt); 2336 checkException(env); 2337 return result; 2338} 2339 2340AutoJObject 2341WebViewCore::getJavaObject() 2342{ 2343 return getRealObject(JSC::Bindings::getJNIEnv(), m_javaGlue->m_obj); 2344} 2345 2346jobject 2347WebViewCore::getWebViewJavaObject() 2348{ 2349 JNIEnv* env = JSC::Bindings::getJNIEnv(); 2350 AutoJObject obj = m_javaGlue->object(env); 2351 // if it is called during DESTROY is handled, the real object of WebViewCore 2352 // can be gone. Check before using it. 2353 if (!obj.get()) 2354 return 0; 2355 return env->GetObjectField(obj.get(), gWebViewCoreFields.m_webView); 2356} 2357 2358void WebViewCore::updateTextSelection() { 2359 WebCore::Node* focusNode = currentFocus(); 2360 if (!focusNode) 2361 return; 2362 RenderObject* renderer = focusNode->renderer(); 2363 if (!renderer || (!renderer->isTextArea() && !renderer->isTextField())) 2364 return; 2365 RenderTextControl* rtc = static_cast<RenderTextControl*>(renderer); 2366 JNIEnv* env = JSC::Bindings::getJNIEnv(); 2367 AutoJObject obj = m_javaGlue->object(env); 2368 // if it is called during DESTROY is handled, the real object of WebViewCore 2369 // can be gone. Check before using it. 2370 if (!obj.get()) 2371 return; 2372 env->CallVoidMethod(obj.get(), 2373 m_javaGlue->m_updateTextSelection, reinterpret_cast<int>(focusNode), 2374 rtc->selectionStart(), rtc->selectionEnd(), m_textGeneration); 2375 checkException(env); 2376} 2377 2378void WebViewCore::updateTextfield(WebCore::Node* ptr, bool changeToPassword, 2379 const WebCore::String& text) 2380{ 2381 if (m_blockTextfieldUpdates) 2382 return; 2383 JNIEnv* env = JSC::Bindings::getJNIEnv(); 2384 AutoJObject obj = m_javaGlue->object(env); 2385 // if it is called during DESTROY is handled, the real object of WebViewCore 2386 // can be gone. Check before using it. 2387 if (!obj.get()) 2388 return; 2389 2390 if (changeToPassword) { 2391 env->CallVoidMethod(obj.get(), m_javaGlue->m_updateTextfield, 2392 (int) ptr, true, 0, m_textGeneration); 2393 checkException(env); 2394 return; 2395 } 2396 int length = text.length(); 2397 jstring string = env->NewString((unsigned short *) text.characters(), length); 2398 env->CallVoidMethod(obj.get(), m_javaGlue->m_updateTextfield, 2399 (int) ptr, false, string, m_textGeneration); 2400 env->DeleteLocalRef(string); 2401 checkException(env); 2402} 2403 2404void WebViewCore::clearTextEntry() 2405{ 2406 JNIEnv* env = JSC::Bindings::getJNIEnv(); 2407 AutoJObject obj = m_javaGlue->object(env); 2408 // if it is called during DESTROY is handled, the real object of WebViewCore 2409 // can be gone. Check before using it. 2410 if (!obj.get()) 2411 return; 2412 2413 env->CallVoidMethod(obj.get(), m_javaGlue->m_clearTextEntry); 2414} 2415 2416void WebViewCore::setBackgroundColor(SkColor c) 2417{ 2418 WebCore::FrameView* view = m_mainFrame->view(); 2419 if (!view) 2420 return; 2421 2422 // need (int) cast to find the right constructor 2423 WebCore::Color bcolor((int)SkColorGetR(c), (int)SkColorGetG(c), 2424 (int)SkColorGetB(c), (int)SkColorGetA(c)); 2425 view->setBaseBackgroundColor(bcolor); 2426} 2427 2428void WebViewCore::startFullScreenPluginActivity(const char* libName, 2429 const char* className, NPP npp) 2430{ 2431 JNIEnv* env = JSC::Bindings::getJNIEnv(); 2432 2433 jstring libString = env->NewStringUTF(libName); 2434 AutoJObject obj = m_javaGlue->object(env); 2435 // if it is called during DESTROY is handled, the real object of WebViewCore 2436 // can be gone. Check before using it. 2437 if (!obj.get()) 2438 return; 2439 2440 jstring classString = env->NewStringUTF(className); 2441 env->CallVoidMethod(obj.get(), 2442 m_javaGlue->m_startFullScreenPluginActivity, 2443 libString, classString, (int) npp); 2444 checkException(env); 2445} 2446 2447jobject WebViewCore::createSurface(const char* libName, const char* className, 2448 NPP npp, int x, int y, int width, int height) 2449{ 2450 JNIEnv* env = JSC::Bindings::getJNIEnv(); 2451 AutoJObject obj = m_javaGlue->object(env); 2452 // if it is called during DESTROY is handled, the real object of WebViewCore 2453 // can be gone. Check before using it. 2454 if (!obj.get()) 2455 return 0; 2456 2457 jstring libString = env->NewStringUTF(libName); 2458 jstring classString = env->NewStringUTF(className); 2459 jobject result = env->CallObjectMethod(obj.get(), 2460 m_javaGlue->m_createSurface, libString, 2461 classString,(int) npp, x, y, width, height); 2462 checkException(env); 2463 return result; 2464 2465} 2466 2467void WebViewCore::updateSurface(jobject childView, int x, int y, int width, int height) 2468{ 2469 JNIEnv* env = JSC::Bindings::getJNIEnv(); 2470 AutoJObject obj = m_javaGlue->object(env); 2471 // if it is called during DESTROY is handled, the real object of WebViewCore 2472 // can be gone. Check before using it. 2473 if (!obj.get()) 2474 return; 2475 2476 env->CallVoidMethod(obj.get(), m_javaGlue->m_updateSurface, childView, x, 2477 y, width, height); 2478 checkException(env); 2479} 2480 2481void WebViewCore::destroySurface(jobject childView) 2482{ 2483 JNIEnv* env = JSC::Bindings::getJNIEnv(); 2484 AutoJObject obj = m_javaGlue->object(env); 2485 // if it is called during DESTROY is handled, the real object of WebViewCore 2486 // can be gone. Check before using it. 2487 if (!obj.get()) 2488 return; 2489 2490 env->CallVoidMethod(obj.get(), m_javaGlue->m_destroySurface, childView); 2491 checkException(env); 2492} 2493 2494//---------------------------------------------------------------------- 2495// Native JNI methods 2496//---------------------------------------------------------------------- 2497static jstring WebCoreStringToJString(JNIEnv *env, WebCore::String string) 2498{ 2499 int length = string.length(); 2500 if (!length) 2501 return 0; 2502 jstring ret = env->NewString((jchar *)string.characters(), length); 2503 env->DeleteLocalRef(ret); 2504 return ret; 2505} 2506 2507static void UpdateFrameCacheIfLoading(JNIEnv *env, jobject obj) 2508{ 2509 GET_NATIVE_VIEW(env, obj)->updateFrameCacheIfLoading(); 2510} 2511 2512static void SetSize(JNIEnv *env, jobject obj, jint width, jint height, 2513 jint screenWidth, jfloat scale, jint realScreenWidth, jint screenHeight, 2514 jboolean ignoreHeight) 2515{ 2516#ifdef ANDROID_INSTRUMENT 2517 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); 2518#endif 2519 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); 2520 LOGV("webviewcore::nativeSetSize(%u %u)\n viewImpl: %p", (unsigned)width, (unsigned)height, viewImpl); 2521 LOG_ASSERT(viewImpl, "viewImpl not set in nativeSetSize"); 2522 viewImpl->setSizeScreenWidthAndScale(width, height, screenWidth, scale, 2523 realScreenWidth, screenHeight, ignoreHeight); 2524} 2525 2526static void SetScrollOffset(JNIEnv *env, jobject obj, jint gen, jint x, jint y) 2527{ 2528#ifdef ANDROID_INSTRUMENT 2529 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); 2530#endif 2531 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); 2532 LOG_ASSERT(viewImpl, "need viewImpl"); 2533 2534 viewImpl->setScrollOffset(gen, x, y); 2535} 2536 2537static void SetGlobalBounds(JNIEnv *env, jobject obj, jint x, jint y, jint h, 2538 jint v) 2539{ 2540#ifdef ANDROID_INSTRUMENT 2541 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); 2542#endif 2543 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); 2544 LOG_ASSERT(viewImpl, "need viewImpl"); 2545 2546 viewImpl->setGlobalBounds(x, y, h, v); 2547} 2548 2549static jboolean Key(JNIEnv *env, jobject obj, jint keyCode, jint unichar, 2550 jint repeatCount, jboolean isShift, jboolean isAlt, jboolean isSym, 2551 jboolean isDown) 2552{ 2553#ifdef ANDROID_INSTRUMENT 2554 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); 2555#endif 2556 return GET_NATIVE_VIEW(env, obj)->key(PlatformKeyboardEvent(keyCode, 2557 unichar, repeatCount, isDown, isShift, isAlt, isSym)); 2558} 2559 2560static void Click(JNIEnv *env, jobject obj, int framePtr, int nodePtr) 2561{ 2562#ifdef ANDROID_INSTRUMENT 2563 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); 2564#endif 2565 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); 2566 LOG_ASSERT(viewImpl, "viewImpl not set in Click"); 2567 2568 viewImpl->click(reinterpret_cast<WebCore::Frame*>(framePtr), 2569 reinterpret_cast<WebCore::Node*>(nodePtr)); 2570} 2571 2572static void DeleteSelection(JNIEnv *env, jobject obj, jint start, jint end, 2573 jint textGeneration) 2574{ 2575#ifdef ANDROID_INSTRUMENT 2576 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); 2577#endif 2578 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); 2579 viewImpl->deleteSelection(start, end, textGeneration); 2580} 2581 2582static void SetSelection(JNIEnv *env, jobject obj, jint start, jint end) 2583{ 2584#ifdef ANDROID_INSTRUMENT 2585 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); 2586#endif 2587 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); 2588 viewImpl->setSelection(start, end); 2589} 2590 2591 2592static void ReplaceTextfieldText(JNIEnv *env, jobject obj, 2593 jint oldStart, jint oldEnd, jstring replace, jint start, jint end, 2594 jint textGeneration) 2595{ 2596#ifdef ANDROID_INSTRUMENT 2597 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); 2598#endif 2599 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); 2600 WebCore::String webcoreString = to_string(env, replace); 2601 viewImpl->replaceTextfieldText(oldStart, 2602 oldEnd, webcoreString, start, end, textGeneration); 2603} 2604 2605static void PassToJs(JNIEnv *env, jobject obj, 2606 jint generation, jstring currentText, jint keyCode, 2607 jint keyValue, jboolean down, jboolean cap, jboolean fn, jboolean sym) 2608{ 2609#ifdef ANDROID_INSTRUMENT 2610 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); 2611#endif 2612 WebCore::String current = to_string(env, currentText); 2613 GET_NATIVE_VIEW(env, obj)->passToJs(generation, current, 2614 PlatformKeyboardEvent(keyCode, keyValue, 0, down, cap, fn, sym)); 2615} 2616 2617static void ScrollFocusedTextInput(JNIEnv *env, jobject obj, jfloat xPercent, 2618 jint y) 2619{ 2620#ifdef ANDROID_INSTRUMENT 2621 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); 2622#endif 2623 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); 2624 viewImpl->scrollFocusedTextInput(xPercent, y); 2625} 2626 2627static void SetFocusControllerActive(JNIEnv *env, jobject obj, jboolean active) 2628{ 2629#ifdef ANDROID_INSTRUMENT 2630 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); 2631#endif 2632 LOGV("webviewcore::nativeSetFocusControllerActive()\n"); 2633 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); 2634 LOG_ASSERT(viewImpl, "viewImpl not set in nativeSetFocusControllerActive"); 2635 viewImpl->setFocusControllerActive(active); 2636} 2637 2638static void SaveDocumentState(JNIEnv *env, jobject obj, jint frame) 2639{ 2640#ifdef ANDROID_INSTRUMENT 2641 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); 2642#endif 2643 LOGV("webviewcore::nativeSaveDocumentState()\n"); 2644 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); 2645 LOG_ASSERT(viewImpl, "viewImpl not set in nativeSaveDocumentState"); 2646 viewImpl->saveDocumentState((WebCore::Frame*) frame); 2647} 2648 2649void WebViewCore::addVisitedLink(const UChar* string, int length) 2650{ 2651 if (m_groupForVisitedLinks) 2652 m_groupForVisitedLinks->addVisitedLink(string, length); 2653} 2654 2655static bool RecordContent(JNIEnv *env, jobject obj, jobject region, jobject pt) 2656{ 2657#ifdef ANDROID_INSTRUMENT 2658 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); 2659#endif 2660 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); 2661 SkRegion* nativeRegion = GraphicsJNI::getNativeRegion(env, region); 2662 SkIPoint nativePt; 2663 bool result = viewImpl->recordContent(nativeRegion, &nativePt); 2664 GraphicsJNI::ipoint_to_jpoint(nativePt, env, pt); 2665 return result; 2666} 2667 2668static void SplitContent(JNIEnv *env, jobject obj) 2669{ 2670#ifdef ANDROID_INSTRUMENT 2671 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); 2672#endif 2673 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); 2674 viewImpl->splitContent(); 2675} 2676 2677static void SendListBoxChoice(JNIEnv* env, jobject obj, jint choice) 2678{ 2679#ifdef ANDROID_INSTRUMENT 2680 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); 2681#endif 2682 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); 2683 LOG_ASSERT(viewImpl, "viewImpl not set in nativeSendListBoxChoice"); 2684 viewImpl->popupReply(choice); 2685} 2686 2687// Set aside a predetermined amount of space in which to place the listbox 2688// choices, to avoid unnecessary allocations. 2689// The size here is arbitrary. We want the size to be at least as great as the 2690// number of items in the average multiple-select listbox. 2691#define PREPARED_LISTBOX_STORAGE 10 2692 2693static void SendListBoxChoices(JNIEnv* env, jobject obj, jbooleanArray jArray, 2694 jint size) 2695{ 2696#ifdef ANDROID_INSTRUMENT 2697 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); 2698#endif 2699 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); 2700 LOG_ASSERT(viewImpl, "viewImpl not set in nativeSendListBoxChoices"); 2701 jboolean* ptrArray = env->GetBooleanArrayElements(jArray, 0); 2702 SkAutoSTMalloc<PREPARED_LISTBOX_STORAGE, int> storage(size); 2703 int* array = storage.get(); 2704 int count = 0; 2705 for (int i = 0; i < size; i++) { 2706 if (ptrArray[i]) { 2707 array[count++] = i; 2708 } 2709 } 2710 env->ReleaseBooleanArrayElements(jArray, ptrArray, JNI_ABORT); 2711 viewImpl->popupReply(array, count); 2712} 2713 2714static jstring FindAddress(JNIEnv *env, jobject obj, jstring addr, 2715 jboolean caseInsensitive) 2716{ 2717#ifdef ANDROID_INSTRUMENT 2718 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); 2719#endif 2720 if (!addr) 2721 return 0; 2722 int length = env->GetStringLength(addr); 2723 if (!length) 2724 return 0; 2725 const jchar* addrChars = env->GetStringChars(addr, 0); 2726 int start, end; 2727 bool success = CacheBuilder::FindAddress(addrChars, length, 2728 &start, &end, caseInsensitive) == CacheBuilder::FOUND_COMPLETE; 2729 jstring ret = 0; 2730 if (success) { 2731 ret = env->NewString((jchar*) addrChars + start, end - start); 2732 env->DeleteLocalRef(ret); 2733 } 2734 env->ReleaseStringChars(addr, addrChars); 2735 return ret; 2736} 2737 2738static jboolean HandleTouchEvent(JNIEnv *env, jobject obj, jint action, jint x, jint y) 2739{ 2740#ifdef ANDROID_INSTRUMENT 2741 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); 2742#endif 2743 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); 2744 LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); 2745 return viewImpl->handleTouchEvent(action, x, y); 2746} 2747 2748static void TouchUp(JNIEnv *env, jobject obj, jint touchGeneration, 2749 jint frame, jint node, jint x, jint y) 2750{ 2751#ifdef ANDROID_INSTRUMENT 2752 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); 2753#endif 2754 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); 2755 LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); 2756 viewImpl->touchUp(touchGeneration, 2757 (WebCore::Frame*) frame, (WebCore::Node*) node, x, y); 2758} 2759 2760static jstring RetrieveHref(JNIEnv *env, jobject obj, jint frame, 2761 jint node) 2762{ 2763#ifdef ANDROID_INSTRUMENT 2764 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); 2765#endif 2766 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); 2767 LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); 2768 WebCore::String result = viewImpl->retrieveHref((WebCore::Frame*) frame, 2769 (WebCore::Node*) node); 2770 if (!result.isEmpty()) 2771 return WebCoreStringToJString(env, result); 2772 return 0; 2773} 2774 2775static void MoveMouse(JNIEnv *env, jobject obj, jint frame, 2776 jint x, jint y) 2777{ 2778#ifdef ANDROID_INSTRUMENT 2779 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); 2780#endif 2781 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); 2782 LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); 2783 viewImpl->moveMouse((WebCore::Frame*) frame, x, y); 2784} 2785 2786static void MoveMouseIfLatest(JNIEnv *env, jobject obj, jint moveGeneration, 2787 jint frame, jint x, jint y) 2788{ 2789#ifdef ANDROID_INSTRUMENT 2790 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); 2791#endif 2792 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); 2793 LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); 2794 viewImpl->moveMouseIfLatest(moveGeneration, 2795 (WebCore::Frame*) frame, x, y); 2796} 2797 2798static void UpdateFrameCache(JNIEnv *env, jobject obj) 2799{ 2800#ifdef ANDROID_INSTRUMENT 2801 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); 2802#endif 2803 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); 2804 LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); 2805 viewImpl->updateFrameCache(); 2806} 2807 2808static jint GetContentMinPrefWidth(JNIEnv *env, jobject obj) 2809{ 2810#ifdef ANDROID_INSTRUMENT 2811 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); 2812#endif 2813 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); 2814 LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); 2815 2816 WebCore::Frame* frame = viewImpl->mainFrame(); 2817 if (frame) { 2818 WebCore::Document* document = frame->document(); 2819 if (document) { 2820 WebCore::RenderObject* renderer = document->renderer(); 2821 if (renderer && renderer->isRenderView()) { 2822 return renderer->minPrefWidth(); 2823 } 2824 } 2825 } 2826 return 0; 2827} 2828 2829static void SetViewportSettingsFromNative(JNIEnv *env, jobject obj) 2830{ 2831#ifdef ANDROID_INSTRUMENT 2832 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); 2833#endif 2834 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); 2835 LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); 2836 2837 WebCore::Settings* s = viewImpl->mainFrame()->page()->settings(); 2838 if (!s) 2839 return; 2840 2841#ifdef ANDROID_META_SUPPORT 2842 env->SetIntField(obj, gWebViewCoreFields.m_viewportWidth, s->viewportWidth()); 2843 env->SetIntField(obj, gWebViewCoreFields.m_viewportHeight, s->viewportHeight()); 2844 env->SetIntField(obj, gWebViewCoreFields.m_viewportInitialScale, s->viewportInitialScale()); 2845 env->SetIntField(obj, gWebViewCoreFields.m_viewportMinimumScale, s->viewportMinimumScale()); 2846 env->SetIntField(obj, gWebViewCoreFields.m_viewportMaximumScale, s->viewportMaximumScale()); 2847 env->SetBooleanField(obj, gWebViewCoreFields.m_viewportUserScalable, s->viewportUserScalable()); 2848 env->SetIntField(obj, gWebViewCoreFields.m_viewportDensityDpi, s->viewportTargetDensityDpi()); 2849#endif 2850} 2851 2852static void SetBackgroundColor(JNIEnv *env, jobject obj, jint color) 2853{ 2854#ifdef ANDROID_INSTRUMENT 2855 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); 2856#endif 2857 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); 2858 LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); 2859 2860 viewImpl->setBackgroundColor((SkColor) color); 2861} 2862 2863static jstring GetSelection(JNIEnv *env, jobject obj, jobject selRgn) 2864{ 2865#ifdef ANDROID_INSTRUMENT 2866 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); 2867#endif 2868 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); 2869 LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); 2870 SkRegion* selectionRegion = GraphicsJNI::getNativeRegion(env, selRgn); 2871 WebCore::String result = viewImpl->getSelection(selectionRegion); 2872 if (!result.isEmpty()) 2873 return WebCoreStringToJString(env, result); 2874 return 0; 2875} 2876 2877static void DumpDomTree(JNIEnv *env, jobject obj, jboolean useFile) 2878{ 2879 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); 2880 LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); 2881 2882 viewImpl->dumpDomTree(useFile); 2883} 2884 2885static void DumpRenderTree(JNIEnv *env, jobject obj, jboolean useFile) 2886{ 2887 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); 2888 LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); 2889 2890 viewImpl->dumpRenderTree(useFile); 2891} 2892 2893static void DumpNavTree(JNIEnv *env, jobject obj) 2894{ 2895 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); 2896 LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); 2897 2898 viewImpl->dumpNavTree(); 2899} 2900 2901static void SetJsFlags(JNIEnv *env, jobject obj, jstring flags) 2902{ 2903#if USE(V8) 2904 WebCore::String flagsString = to_string(env, flags); 2905 WebCore::CString utf8String = flagsString.utf8(); 2906 WebCore::ScriptController::setFlags(utf8String.data(), utf8String.length()); 2907#endif 2908} 2909 2910 2911// Called from the Java side to set a new quota for the origin or new appcache 2912// max size in response to a notification that the original quota was exceeded or 2913// that the appcache has reached its maximum size. 2914static void SetNewStorageLimit(JNIEnv* env, jobject obj, jlong quota) { 2915#if ENABLE(DATABASE) || ENABLE(OFFLINE_WEB_APPLICATIONS) 2916 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); 2917 Frame* frame = viewImpl->mainFrame(); 2918 2919 // The main thread is blocked awaiting this response, so now we can wake it 2920 // up. 2921 ChromeClientAndroid* chromeC = static_cast<ChromeClientAndroid*>(frame->page()->chrome()->client()); 2922 chromeC->wakeUpMainThreadWithNewQuota(quota); 2923#endif 2924} 2925 2926// Called from Java to provide a Geolocation permission state for the specified origin. 2927static void GeolocationPermissionsProvide(JNIEnv* env, jobject obj, jstring origin, jboolean allow, jboolean remember) { 2928 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); 2929 Frame* frame = viewImpl->mainFrame(); 2930 2931 ChromeClientAndroid* chromeClient = static_cast<ChromeClientAndroid*>(frame->page()->chrome()->client()); 2932 chromeClient->provideGeolocationPermissions(to_string(env, origin), allow, remember); 2933} 2934 2935static void RegisterURLSchemeAsLocal(JNIEnv* env, jobject obj, jstring scheme) { 2936#ifdef ANDROID_INSTRUMENT 2937 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); 2938#endif 2939 WebCore::SecurityOrigin::registerURLSchemeAsLocal(to_string(env, scheme)); 2940} 2941 2942static void ClearContent(JNIEnv *env, jobject obj) 2943{ 2944#ifdef ANDROID_INSTRUMENT 2945 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); 2946#endif 2947 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); 2948 viewImpl->clearContent(); 2949} 2950 2951static void CopyContentToPicture(JNIEnv *env, jobject obj, jobject pict) 2952{ 2953#ifdef ANDROID_INSTRUMENT 2954 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); 2955#endif 2956 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); 2957 if (!viewImpl) 2958 return; 2959 SkPicture* picture = GraphicsJNI::getNativePicture(env, pict); 2960 viewImpl->copyContentToPicture(picture); 2961} 2962 2963static bool DrawContent(JNIEnv *env, jobject obj, jobject canv, jint color) 2964{ 2965 // Note: this is called from UI thread, don't count it for WebViewCoreTimeCounter 2966 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); 2967 SkCanvas* canvas = GraphicsJNI::getNativeCanvas(env, canv); 2968 return viewImpl->drawContent(canvas, color); 2969} 2970 2971static bool FocusBoundsChanged(JNIEnv* env, jobject obj) 2972{ 2973 return GET_NATIVE_VIEW(env, obj)->focusBoundsChanged(); 2974} 2975 2976static bool PictureReady(JNIEnv* env, jobject obj) 2977{ 2978 return GET_NATIVE_VIEW(env, obj)->pictureReady(); 2979} 2980 2981static void Pause(JNIEnv* env, jobject obj) 2982{ 2983 // This is called for the foreground tab when the browser is put to the 2984 // background (and also for any tab when it is put to the background of the 2985 // browser). The browser can only be killed by the system when it is in the 2986 // background, so saving the Geolocation permission state now ensures that 2987 // is maintained when the browser is killed. 2988 ChromeClient* chromeClient = GET_NATIVE_VIEW(env, obj)->mainFrame()->page()->chrome()->client(); 2989 ChromeClientAndroid* chromeClientAndroid = static_cast<ChromeClientAndroid*>(chromeClient); 2990 chromeClientAndroid->storeGeolocationPermissions(); 2991 2992 Frame* mainFrame = GET_NATIVE_VIEW(env, obj)->mainFrame(); 2993 for (Frame* frame = mainFrame; frame; frame = frame->tree()->traverseNext()) { 2994 Geolocation* geolocation = frame->domWindow()->navigator()->optionalGeolocation(); 2995 if (geolocation) 2996 geolocation->suspend(); 2997 } 2998 2999 ANPEvent event; 3000 SkANP::InitEvent(&event, kLifecycle_ANPEventType); 3001 event.data.lifecycle.action = kPause_ANPLifecycleAction; 3002 GET_NATIVE_VIEW(env, obj)->sendPluginEvent(event); 3003} 3004 3005static void Resume(JNIEnv* env, jobject obj) 3006{ 3007 Frame* mainFrame = GET_NATIVE_VIEW(env, obj)->mainFrame(); 3008 for (Frame* frame = mainFrame; frame; frame = frame->tree()->traverseNext()) { 3009 Geolocation* geolocation = frame->domWindow()->navigator()->optionalGeolocation(); 3010 if (geolocation) 3011 geolocation->resume(); 3012 } 3013 3014 ANPEvent event; 3015 SkANP::InitEvent(&event, kLifecycle_ANPEventType); 3016 event.data.lifecycle.action = kResume_ANPLifecycleAction; 3017 GET_NATIVE_VIEW(env, obj)->sendPluginEvent(event); 3018} 3019 3020static void FreeMemory(JNIEnv* env, jobject obj) 3021{ 3022 ANPEvent event; 3023 SkANP::InitEvent(&event, kLifecycle_ANPEventType); 3024 event.data.lifecycle.action = kFreeMemory_ANPLifecycleAction; 3025 GET_NATIVE_VIEW(env, obj)->sendPluginEvent(event); 3026} 3027 3028static void ProvideVisitedHistory(JNIEnv *env, jobject obj, jobject hist) 3029{ 3030 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); 3031 LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); 3032 3033 jobjectArray array = static_cast<jobjectArray>(hist); 3034 3035 jsize len = env->GetArrayLength(array); 3036 for (jsize i = 0; i < len; i++) { 3037 jstring item = static_cast<jstring>(env->GetObjectArrayElement(array, i)); 3038 const UChar* str = static_cast<const UChar*>(env->GetStringChars(item, NULL)); 3039 jsize len = env->GetStringLength(item); 3040 viewImpl->addVisitedLink(str, len); 3041 env->ReleaseStringChars(item, str); 3042 env->DeleteLocalRef(item); 3043 } 3044 env->DeleteLocalRef(array); 3045} 3046 3047// ---------------------------------------------------------------------------- 3048 3049/* 3050 * JNI registration. 3051 */ 3052static JNINativeMethod gJavaWebViewCoreMethods[] = { 3053 { "nativeClearContent", "()V", 3054 (void*) ClearContent }, 3055 { "nativeCopyContentToPicture", "(Landroid/graphics/Picture;)V", 3056 (void*) CopyContentToPicture }, 3057 { "nativeDrawContent", "(Landroid/graphics/Canvas;I)Z", 3058 (void*) DrawContent } , 3059 { "nativeFocusBoundsChanged", "()Z", 3060 (void*) FocusBoundsChanged } , 3061 { "nativeKey", "(IIIZZZZ)Z", 3062 (void*) Key }, 3063 { "nativeClick", "(II)V", 3064 (void*) Click }, 3065 { "nativePictureReady", "()Z", 3066 (void*) PictureReady } , 3067 { "nativeSendListBoxChoices", "([ZI)V", 3068 (void*) SendListBoxChoices }, 3069 { "nativeSendListBoxChoice", "(I)V", 3070 (void*) SendListBoxChoice }, 3071 { "nativeSetSize", "(IIIFIIZ)V", 3072 (void*) SetSize }, 3073 { "nativeSetScrollOffset", "(III)V", 3074 (void*) SetScrollOffset }, 3075 { "nativeSetGlobalBounds", "(IIII)V", 3076 (void*) SetGlobalBounds }, 3077 { "nativeSetSelection", "(II)V", 3078 (void*) SetSelection } , 3079 { "nativeDeleteSelection", "(III)V", 3080 (void*) DeleteSelection } , 3081 { "nativeReplaceTextfieldText", "(IILjava/lang/String;III)V", 3082 (void*) ReplaceTextfieldText } , 3083 { "nativeMoveMouse", "(III)V", 3084 (void*) MoveMouse }, 3085 { "nativeMoveMouseIfLatest", "(IIII)V", 3086 (void*) MoveMouseIfLatest }, 3087 { "passToJs", "(ILjava/lang/String;IIZZZZ)V", 3088 (void*) PassToJs }, 3089 { "nativeScrollFocusedTextInput", "(FI)V", 3090 (void*) ScrollFocusedTextInput }, 3091 { "nativeSetFocusControllerActive", "(Z)V", 3092 (void*) SetFocusControllerActive }, 3093 { "nativeSaveDocumentState", "(I)V", 3094 (void*) SaveDocumentState }, 3095 { "nativeFindAddress", "(Ljava/lang/String;Z)Ljava/lang/String;", 3096 (void*) FindAddress }, 3097 { "nativeHandleTouchEvent", "(III)Z", 3098 (void*) HandleTouchEvent }, 3099 { "nativeTouchUp", "(IIIII)V", 3100 (void*) TouchUp }, 3101 { "nativeRetrieveHref", "(II)Ljava/lang/String;", 3102 (void*) RetrieveHref }, 3103 { "nativeUpdateFrameCache", "()V", 3104 (void*) UpdateFrameCache }, 3105 { "nativeGetContentMinPrefWidth", "()I", 3106 (void*) GetContentMinPrefWidth }, 3107 { "nativeRecordContent", "(Landroid/graphics/Region;Landroid/graphics/Point;)Z", 3108 (void*) RecordContent }, 3109 { "setViewportSettingsFromNative", "()V", 3110 (void*) SetViewportSettingsFromNative }, 3111 { "nativeSplitContent", "()V", 3112 (void*) SplitContent }, 3113 { "nativeSetBackgroundColor", "(I)V", 3114 (void*) SetBackgroundColor }, 3115 { "nativeGetSelection", "(Landroid/graphics/Region;)Ljava/lang/String;", 3116 (void*) GetSelection }, 3117 { "nativeRegisterURLSchemeAsLocal", "(Ljava/lang/String;)V", 3118 (void*) RegisterURLSchemeAsLocal }, 3119 { "nativeDumpDomTree", "(Z)V", 3120 (void*) DumpDomTree }, 3121 { "nativeDumpRenderTree", "(Z)V", 3122 (void*) DumpRenderTree }, 3123 { "nativeDumpNavTree", "()V", 3124 (void*) DumpNavTree }, 3125 { "nativeSetNewStorageLimit", "(J)V", 3126 (void*) SetNewStorageLimit }, 3127 { "nativeGeolocationPermissionsProvide", "(Ljava/lang/String;ZZ)V", 3128 (void*) GeolocationPermissionsProvide }, 3129 { "nativePause", "()V", (void*) Pause }, 3130 { "nativeResume", "()V", (void*) Resume }, 3131 { "nativeFreeMemory", "()V", (void*) FreeMemory }, 3132 { "nativeSetJsFlags", "(Ljava/lang/String;)V", (void*) SetJsFlags }, 3133 { "nativeUpdateFrameCacheIfLoading", "()V", 3134 (void*) UpdateFrameCacheIfLoading }, 3135 { "nativeProvideVisitedHistory", "([Ljava/lang/String;)V", 3136 (void*) ProvideVisitedHistory }, 3137}; 3138 3139int register_webviewcore(JNIEnv* env) 3140{ 3141 jclass widget = env->FindClass("android/webkit/WebViewCore"); 3142 LOG_ASSERT(widget, 3143 "Unable to find class android/webkit/WebViewCore"); 3144 gWebViewCoreFields.m_nativeClass = env->GetFieldID(widget, "mNativeClass", 3145 "I"); 3146 LOG_ASSERT(gWebViewCoreFields.m_nativeClass, 3147 "Unable to find android/webkit/WebViewCore.mNativeClass"); 3148 gWebViewCoreFields.m_viewportWidth = env->GetFieldID(widget, 3149 "mViewportWidth", "I"); 3150 LOG_ASSERT(gWebViewCoreFields.m_viewportWidth, 3151 "Unable to find android/webkit/WebViewCore.mViewportWidth"); 3152 gWebViewCoreFields.m_viewportHeight = env->GetFieldID(widget, 3153 "mViewportHeight", "I"); 3154 LOG_ASSERT(gWebViewCoreFields.m_viewportHeight, 3155 "Unable to find android/webkit/WebViewCore.mViewportHeight"); 3156 gWebViewCoreFields.m_viewportInitialScale = env->GetFieldID(widget, 3157 "mViewportInitialScale", "I"); 3158 LOG_ASSERT(gWebViewCoreFields.m_viewportInitialScale, 3159 "Unable to find android/webkit/WebViewCore.mViewportInitialScale"); 3160 gWebViewCoreFields.m_viewportMinimumScale = env->GetFieldID(widget, 3161 "mViewportMinimumScale", "I"); 3162 LOG_ASSERT(gWebViewCoreFields.m_viewportMinimumScale, 3163 "Unable to find android/webkit/WebViewCore.mViewportMinimumScale"); 3164 gWebViewCoreFields.m_viewportMaximumScale = env->GetFieldID(widget, 3165 "mViewportMaximumScale", "I"); 3166 LOG_ASSERT(gWebViewCoreFields.m_viewportMaximumScale, 3167 "Unable to find android/webkit/WebViewCore.mViewportMaximumScale"); 3168 gWebViewCoreFields.m_viewportUserScalable = env->GetFieldID(widget, 3169 "mViewportUserScalable", "Z"); 3170 LOG_ASSERT(gWebViewCoreFields.m_viewportUserScalable, 3171 "Unable to find android/webkit/WebViewCore.mViewportUserScalable"); 3172 gWebViewCoreFields.m_viewportDensityDpi = env->GetFieldID(widget, 3173 "mViewportDensityDpi", "I"); 3174 LOG_ASSERT(gWebViewCoreFields.m_viewportDensityDpi, 3175 "Unable to find android/webkit/WebViewCore.mViewportDensityDpi"); 3176 gWebViewCoreFields.m_webView = env->GetFieldID(widget, 3177 "mWebView", "Landroid/webkit/WebView;"); 3178 LOG_ASSERT(gWebViewCoreFields.m_webView, 3179 "Unable to find android/webkit/WebViewCore.mWebView"); 3180 3181 return jniRegisterNativeMethods(env, "android/webkit/WebViewCore", 3182 gJavaWebViewCoreMethods, NELEM(gJavaWebViewCoreMethods)); 3183} 3184 3185} /* namespace android */ 3186