WebView.cpp revision 57ae1393d3097edada2640b40c895396b69cc919
1/* 2 * Copyright 2007, The Android Open Source Project 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * * Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * * Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY 14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26#define LOG_TAG "webviewglue" 27 28#include "config.h" 29 30#include "AndroidAnimation.h" 31#include "AndroidLog.h" 32#include "BaseLayerAndroid.h" 33#include "DrawExtra.h" 34#include "Frame.h" 35#include "GraphicsJNI.h" 36#include "HTMLInputElement.h" 37#include "IntPoint.h" 38#include "IntRect.h" 39#include "LayerAndroid.h" 40#include "Node.h" 41#include "utils/Functor.h" 42#include "private/hwui/DrawGlInfo.h" 43#include "PlatformGraphicsContext.h" 44#include "PlatformString.h" 45#include "ScrollableLayerAndroid.h" 46#include "SelectText.h" 47#include "SkCanvas.h" 48#include "SkDumpCanvas.h" 49#include "SkPicture.h" 50#include "SkRect.h" 51#include "SkTime.h" 52#include "TilesManager.h" 53#include "WebCoreJni.h" 54#include "WebRequestContext.h" 55#include "WebViewCore.h" 56#include "android_graphics.h" 57 58#ifdef GET_NATIVE_VIEW 59#undef GET_NATIVE_VIEW 60#endif 61 62#define GET_NATIVE_VIEW(env, obj) ((WebView*)env->GetIntField(obj, gWebViewField)) 63 64#include <JNIUtility.h> 65#include <JNIHelp.h> 66#include <jni.h> 67#include <androidfw/KeycodeLabels.h> 68#include <wtf/text/AtomicString.h> 69#include <wtf/text/CString.h> 70 71// Free as much as we possible can 72#define TRIM_MEMORY_COMPLETE 80 73// Free a lot (all textures gone) 74#define TRIM_MEMORY_MODERATE 60 75// More moderate free (keep bare minimum to restore quickly-ish - possibly clear all textures) 76#define TRIM_MEMORY_BACKGROUND 40 77// Moderate free (clear cached tiles, keep visible ones) 78#define TRIM_MEMORY_UI_HIDDEN 20 79// Duration to show the pressed cursor ring 80#define PRESSED_STATE_DURATION 400 81 82namespace android { 83 84static jfieldID gWebViewField; 85 86//------------------------------------- 87 88static jmethodID GetJMethod(JNIEnv* env, jclass clazz, const char name[], const char signature[]) 89{ 90 jmethodID m = env->GetMethodID(clazz, name, signature); 91 ALOG_ASSERT(m, "Could not find method %s", name); 92 return m; 93} 94 95//------------------------------------- 96// This class provides JNI for making calls into native code from the UI side 97// of the multi-threaded WebView. 98class WebView 99{ 100public: 101enum FrameCachePermission { 102 DontAllowNewer, 103 AllowNewer 104}; 105 106#define DRAW_EXTRAS_SIZE 2 107enum DrawExtras { // keep this in sync with WebView.java 108 DrawExtrasNone = 0, 109 DrawExtrasSelection = 1, 110 DrawExtrasCursorRing = 2 111}; 112 113struct JavaGlue { 114 jweak m_obj; 115 jmethodID m_overrideLoading; 116 jmethodID m_scrollBy; 117 jmethodID m_sendMoveFocus; 118 jmethodID m_sendMoveMouse; 119 jmethodID m_sendMoveMouseIfLatest; 120 jmethodID m_sendMotionUp; 121 jmethodID m_domChangedFocus; 122 jmethodID m_getScaledMaxXScroll; 123 jmethodID m_getScaledMaxYScroll; 124 jmethodID m_getVisibleRect; 125 jmethodID m_rebuildWebTextView; 126 jmethodID m_viewInvalidate; 127 jmethodID m_viewInvalidateRect; 128 jmethodID m_postInvalidateDelayed; 129 jmethodID m_pageSwapCallback; 130 jfieldID m_rectLeft; 131 jfieldID m_rectTop; 132 jmethodID m_rectWidth; 133 jmethodID m_rectHeight; 134 jfieldID m_rectFLeft; 135 jfieldID m_rectFTop; 136 jmethodID m_rectFWidth; 137 jmethodID m_rectFHeight; 138 AutoJObject object(JNIEnv* env) { 139 return getRealObject(env, m_obj); 140 } 141} m_javaGlue; 142 143WebView(JNIEnv* env, jobject javaWebView, int viewImpl, WTF::String drawableDir, 144 bool isHighEndGfx) 145 : m_isHighEndGfx(isHighEndGfx) 146{ 147 memset(m_extras, 0, DRAW_EXTRAS_SIZE * sizeof(DrawExtra*)); 148 jclass clazz = env->FindClass("android/webkit/WebViewClassic"); 149 // m_javaGlue = new JavaGlue; 150 m_javaGlue.m_obj = env->NewWeakGlobalRef(javaWebView); 151 m_javaGlue.m_scrollBy = GetJMethod(env, clazz, "setContentScrollBy", "(IIZ)Z"); 152 m_javaGlue.m_overrideLoading = GetJMethod(env, clazz, "overrideLoading", "(Ljava/lang/String;)V"); 153 m_javaGlue.m_sendMoveFocus = GetJMethod(env, clazz, "sendMoveFocus", "(II)V"); 154 m_javaGlue.m_sendMoveMouse = GetJMethod(env, clazz, "sendMoveMouse", "(IIII)V"); 155 m_javaGlue.m_sendMoveMouseIfLatest = GetJMethod(env, clazz, "sendMoveMouseIfLatest", "(ZZ)V"); 156 m_javaGlue.m_sendMotionUp = GetJMethod(env, clazz, "sendMotionUp", "(IIIII)V"); 157 m_javaGlue.m_domChangedFocus = GetJMethod(env, clazz, "domChangedFocus", "()V"); 158 m_javaGlue.m_getScaledMaxXScroll = GetJMethod(env, clazz, "getScaledMaxXScroll", "()I"); 159 m_javaGlue.m_getScaledMaxYScroll = GetJMethod(env, clazz, "getScaledMaxYScroll", "()I"); 160 m_javaGlue.m_getVisibleRect = GetJMethod(env, clazz, "sendOurVisibleRect", "()Landroid/graphics/Rect;"); 161 m_javaGlue.m_rebuildWebTextView = GetJMethod(env, clazz, "rebuildWebTextView", "()V"); 162 m_javaGlue.m_viewInvalidate = GetJMethod(env, clazz, "viewInvalidate", "()V"); 163 m_javaGlue.m_viewInvalidateRect = GetJMethod(env, clazz, "viewInvalidate", "(IIII)V"); 164 m_javaGlue.m_postInvalidateDelayed = GetJMethod(env, clazz, 165 "viewInvalidateDelayed", "(JIIII)V"); 166 m_javaGlue.m_pageSwapCallback = GetJMethod(env, clazz, "pageSwapCallback", "(Z)V"); 167 env->DeleteLocalRef(clazz); 168 169 jclass rectClass = env->FindClass("android/graphics/Rect"); 170 ALOG_ASSERT(rectClass, "Could not find Rect class"); 171 m_javaGlue.m_rectLeft = env->GetFieldID(rectClass, "left", "I"); 172 m_javaGlue.m_rectTop = env->GetFieldID(rectClass, "top", "I"); 173 m_javaGlue.m_rectWidth = GetJMethod(env, rectClass, "width", "()I"); 174 m_javaGlue.m_rectHeight = GetJMethod(env, rectClass, "height", "()I"); 175 env->DeleteLocalRef(rectClass); 176 177 jclass rectClassF = env->FindClass("android/graphics/RectF"); 178 ALOG_ASSERT(rectClassF, "Could not find RectF class"); 179 m_javaGlue.m_rectFLeft = env->GetFieldID(rectClassF, "left", "F"); 180 m_javaGlue.m_rectFTop = env->GetFieldID(rectClassF, "top", "F"); 181 m_javaGlue.m_rectFWidth = GetJMethod(env, rectClassF, "width", "()F"); 182 m_javaGlue.m_rectFHeight = GetJMethod(env, rectClassF, "height", "()F"); 183 env->DeleteLocalRef(rectClassF); 184 185 env->SetIntField(javaWebView, gWebViewField, (jint)this); 186 m_viewImpl = (WebViewCore*) viewImpl; 187 m_generation = 0; 188 m_heightCanMeasure = false; 189 m_lastDx = 0; 190 m_lastDxTime = 0; 191 m_baseLayer = 0; 192 m_glDrawFunctor = 0; 193 m_isDrawingPaused = false; 194#if USE(ACCELERATED_COMPOSITING) 195 m_glWebViewState = 0; 196#endif 197} 198 199~WebView() 200{ 201 if (m_javaGlue.m_obj) 202 { 203 JNIEnv* env = JSC::Bindings::getJNIEnv(); 204 env->DeleteWeakGlobalRef(m_javaGlue.m_obj); 205 m_javaGlue.m_obj = 0; 206 } 207#if USE(ACCELERATED_COMPOSITING) 208 // We must remove the m_glWebViewState prior to deleting m_baseLayer. If we 209 // do not remove it here, we risk having BaseTiles trying to paint using a 210 // deallocated base layer. 211 stopGL(); 212#endif 213 SkSafeUnref(m_baseLayer); 214 delete m_glDrawFunctor; 215 for (int i = 0; i < DRAW_EXTRAS_SIZE; i++) 216 delete m_extras[i]; 217} 218 219DrawExtra* getDrawExtra(DrawExtras extras) 220{ 221 if (extras == DrawExtrasNone) 222 return 0; 223 return m_extras[extras - 1]; 224} 225 226void stopGL() 227{ 228#if USE(ACCELERATED_COMPOSITING) 229 delete m_glWebViewState; 230 m_glWebViewState = 0; 231#endif 232} 233 234WebViewCore* getWebViewCore() const { 235 return m_viewImpl; 236} 237 238void scrollRectOnScreen(const IntRect& rect) 239{ 240 if (rect.isEmpty()) 241 return; 242 int dx = 0; 243 int left = rect.x(); 244 int right = rect.maxX(); 245 if (left < m_visibleRect.fLeft) 246 dx = left - m_visibleRect.fLeft; 247 // Only scroll right if the entire width can fit on screen. 248 else if (right > m_visibleRect.fRight 249 && right - left < m_visibleRect.width()) 250 dx = right - m_visibleRect.fRight; 251 int dy = 0; 252 int top = rect.y(); 253 int bottom = rect.maxY(); 254 if (top < m_visibleRect.fTop) 255 dy = top - m_visibleRect.fTop; 256 // Only scroll down if the entire height can fit on screen 257 else if (bottom > m_visibleRect.fBottom 258 && bottom - top < m_visibleRect.height()) 259 dy = bottom - m_visibleRect.fBottom; 260 if ((dx|dy) == 0 || !scrollBy(dx, dy)) 261 return; 262 viewInvalidate(); 263} 264 265bool drawGL(WebCore::IntRect& viewRect, WebCore::IntRect* invalRect, 266 WebCore::IntRect& webViewRect, int titleBarHeight, 267 WebCore::IntRect& clip, float scale, int extras) 268{ 269#if USE(ACCELERATED_COMPOSITING) 270 if (!m_baseLayer) 271 return false; 272 273 if (!m_glWebViewState) { 274 TilesManager::instance()->setHighEndGfx(m_isHighEndGfx); 275 m_glWebViewState = new GLWebViewState(); 276 if (m_baseLayer->content()) { 277 SkRegion region; 278 SkIRect rect; 279 rect.set(0, 0, m_baseLayer->content()->width(), m_baseLayer->content()->height()); 280 region.setRect(rect); 281 m_baseLayer->markAsDirty(region); 282 m_glWebViewState->setBaseLayer(m_baseLayer, false, true); 283 } 284 } 285 286 DrawExtra* extra = getDrawExtra((DrawExtras) extras); 287 288 unsigned int pic = m_glWebViewState->currentPictureCounter(); 289 m_glWebViewState->glExtras()->setDrawExtra(extra); 290 291 // Make sure we have valid coordinates. We might not have valid coords 292 // if the zoom manager is still initializing. We will be redrawn 293 // once the correct scale is set 294 if (!m_visibleRect.isFinite()) 295 return false; 296 bool treesSwapped = false; 297 bool newTreeHasAnim = false; 298 bool ret = m_glWebViewState->drawGL(viewRect, m_visibleRect, invalRect, 299 webViewRect, titleBarHeight, clip, scale, 300 &treesSwapped, &newTreeHasAnim); 301 if (treesSwapped) { 302 ALOG_ASSERT(m_javaGlue.m_obj, "A java object was not associated with this native WebView!"); 303 JNIEnv* env = JSC::Bindings::getJNIEnv(); 304 AutoJObject javaObject = m_javaGlue.object(env); 305 if (javaObject.get()) { 306 env->CallVoidMethod(javaObject.get(), m_javaGlue.m_pageSwapCallback, newTreeHasAnim); 307 checkException(env); 308 } 309 } 310 if (ret || m_glWebViewState->currentPictureCounter() != pic) 311 return !m_isDrawingPaused; 312#endif 313 return false; 314} 315 316PictureSet* draw(SkCanvas* canvas, SkColor bgColor, DrawExtras extras, bool split) 317{ 318 PictureSet* ret = 0; 319 if (!m_baseLayer) { 320 canvas->drawColor(bgColor); 321 return ret; 322 } 323 324 // draw the content of the base layer first 325 PictureSet* content = m_baseLayer->content(); 326 int sc = canvas->save(SkCanvas::kClip_SaveFlag); 327 canvas->clipRect(SkRect::MakeLTRB(0, 0, content->width(), 328 content->height()), SkRegion::kDifference_Op); 329 canvas->drawColor(bgColor); 330 canvas->restoreToCount(sc); 331 if (content->draw(canvas)) 332 ret = split ? new PictureSet(*content) : 0; 333 334 DrawExtra* extra = getDrawExtra(extras); 335 if (extra) 336 extra->draw(canvas, 0); 337 338#if USE(ACCELERATED_COMPOSITING) 339 LayerAndroid* compositeLayer = compositeRoot(); 340 if (compositeLayer) { 341 // call this to be sure we've adjusted for any scrolling or animations 342 // before we actually draw 343 compositeLayer->updateFixedLayersPositions(m_visibleRect); 344 compositeLayer->updatePositions(); 345 // We have to set the canvas' matrix on the base layer 346 // (to have fixed layers work as intended) 347 SkAutoCanvasRestore restore(canvas, true); 348 m_baseLayer->setMatrix(canvas->getTotalMatrix()); 349 canvas->resetMatrix(); 350 m_baseLayer->draw(canvas, extra); 351 } 352 if (extra) { 353 IntRect dummy; // inval area, unused for now 354 extra->drawLegacy(canvas, compositeLayer, &dummy); 355 } 356#endif 357 return ret; 358} 359 360int getScaledMaxXScroll() 361{ 362 ALOG_ASSERT(m_javaGlue.m_obj, "A java object was not associated with this native WebView!"); 363 JNIEnv* env = JSC::Bindings::getJNIEnv(); 364 AutoJObject javaObject = m_javaGlue.object(env); 365 if (!javaObject.get()) 366 return 0; 367 int result = env->CallIntMethod(javaObject.get(), m_javaGlue.m_getScaledMaxXScroll); 368 checkException(env); 369 return result; 370} 371 372int getScaledMaxYScroll() 373{ 374 ALOG_ASSERT(m_javaGlue.m_obj, "A java object was not associated with this native WebView!"); 375 JNIEnv* env = JSC::Bindings::getJNIEnv(); 376 AutoJObject javaObject = m_javaGlue.object(env); 377 if (!javaObject.get()) 378 return 0; 379 int result = env->CallIntMethod(javaObject.get(), m_javaGlue.m_getScaledMaxYScroll); 380 checkException(env); 381 return result; 382} 383 384IntRect getVisibleRect() 385{ 386 IntRect rect; 387 ALOG_ASSERT(m_javaGlue.m_obj, "A java object was not associated with this native WebView!"); 388 JNIEnv* env = JSC::Bindings::getJNIEnv(); 389 AutoJObject javaObject = m_javaGlue.object(env); 390 if (!javaObject.get()) 391 return rect; 392 jobject jRect = env->CallObjectMethod(javaObject.get(), m_javaGlue.m_getVisibleRect); 393 checkException(env); 394 rect.setX(env->GetIntField(jRect, m_javaGlue.m_rectLeft)); 395 checkException(env); 396 rect.setY(env->GetIntField(jRect, m_javaGlue.m_rectTop)); 397 checkException(env); 398 rect.setWidth(env->CallIntMethod(jRect, m_javaGlue.m_rectWidth)); 399 checkException(env); 400 rect.setHeight(env->CallIntMethod(jRect, m_javaGlue.m_rectHeight)); 401 checkException(env); 402 env->DeleteLocalRef(jRect); 403 checkException(env); 404 return rect; 405} 406 407void notifyProgressFinished() 408{ 409 rebuildWebTextView(); 410} 411 412#if USE(ACCELERATED_COMPOSITING) 413static const ScrollableLayerAndroid* findScrollableLayer( 414 const LayerAndroid* parent, int x, int y, SkIRect* foundBounds) { 415 SkRect bounds; 416 parent->bounds(&bounds); 417 // Check the parent bounds first; this will clip to within a masking layer's 418 // bounds. 419 if (parent->masksToBounds() && !bounds.contains(x, y)) 420 return 0; 421 // Move the hit test local to parent. 422 x -= bounds.fLeft; 423 y -= bounds.fTop; 424 int count = parent->countChildren(); 425 while (count--) { 426 const LayerAndroid* child = parent->getChild(count); 427 const ScrollableLayerAndroid* result = findScrollableLayer(child, x, y, 428 foundBounds); 429 if (result) { 430 foundBounds->offset(bounds.fLeft, bounds.fTop); 431 if (parent->masksToBounds()) { 432 if (bounds.width() < foundBounds->width()) 433 foundBounds->fRight = foundBounds->fLeft + bounds.width(); 434 if (bounds.height() < foundBounds->height()) 435 foundBounds->fBottom = foundBounds->fTop + bounds.height(); 436 } 437 return result; 438 } 439 } 440 if (parent->contentIsScrollable()) { 441 foundBounds->set(0, 0, bounds.width(), bounds.height()); 442 return static_cast<const ScrollableLayerAndroid*>(parent); 443 } 444 return 0; 445} 446#endif 447 448int scrollableLayer(int x, int y, SkIRect* layerRect, SkIRect* bounds) 449{ 450#if USE(ACCELERATED_COMPOSITING) 451 const LayerAndroid* layerRoot = compositeRoot(); 452 if (!layerRoot) 453 return 0; 454 const ScrollableLayerAndroid* result = findScrollableLayer(layerRoot, x, y, 455 bounds); 456 if (result) { 457 result->getScrollRect(layerRect); 458 return result->uniqueId(); 459 } 460#endif 461 return 0; 462} 463 464void scrollLayer(int layerId, int x, int y) 465{ 466 if (m_glWebViewState) 467 m_glWebViewState->scrollLayer(layerId, x, y); 468} 469 470void overrideUrlLoading(const WTF::String& url) 471{ 472 JNIEnv* env = JSC::Bindings::getJNIEnv(); 473 AutoJObject javaObject = m_javaGlue.object(env); 474 if (!javaObject.get()) 475 return; 476 jstring jName = wtfStringToJstring(env, url); 477 env->CallVoidMethod(javaObject.get(), m_javaGlue.m_overrideLoading, jName); 478 env->DeleteLocalRef(jName); 479} 480 481void setFindIsUp(bool up) 482{ 483 m_viewImpl->m_findIsUp = up; 484} 485 486void setHeightCanMeasure(bool measure) 487{ 488 m_heightCanMeasure = measure; 489} 490 491String getSelection() 492{ 493 SelectText* select = static_cast<SelectText*>( 494 getDrawExtra(WebView::DrawExtrasSelection)); 495 if (select) 496 return select->getText(); 497 return String(); 498} 499 500void sendMoveFocus(WebCore::Frame* framePtr, WebCore::Node* nodePtr) 501{ 502 JNIEnv* env = JSC::Bindings::getJNIEnv(); 503 AutoJObject javaObject = m_javaGlue.object(env); 504 if (!javaObject.get()) 505 return; 506 env->CallVoidMethod(javaObject.get(), m_javaGlue.m_sendMoveFocus, (jint) framePtr, (jint) nodePtr); 507 checkException(env); 508} 509 510void sendMoveMouse(WebCore::Frame* framePtr, WebCore::Node* nodePtr, int x, int y) 511{ 512 JNIEnv* env = JSC::Bindings::getJNIEnv(); 513 AutoJObject javaObject = m_javaGlue.object(env); 514 if (!javaObject.get()) 515 return; 516 env->CallVoidMethod(javaObject.get(), m_javaGlue.m_sendMoveMouse, reinterpret_cast<jint>(framePtr), reinterpret_cast<jint>(nodePtr), x, y); 517 checkException(env); 518} 519 520void sendMoveMouseIfLatest(bool clearTextEntry, bool stopPaintingCaret) 521{ 522 ALOG_ASSERT(m_javaGlue.m_obj, "A java object was not associated with this native WebView!"); 523 JNIEnv* env = JSC::Bindings::getJNIEnv(); 524 AutoJObject javaObject = m_javaGlue.object(env); 525 if (!javaObject.get()) 526 return; 527 env->CallVoidMethod(javaObject.get(), m_javaGlue.m_sendMoveMouseIfLatest, clearTextEntry, stopPaintingCaret); 528 checkException(env); 529} 530 531void sendMotionUp(WebCore::Frame* framePtr, WebCore::Node* nodePtr, int x, int y) 532{ 533 ALOG_ASSERT(m_javaGlue.m_obj, "A WebView was not associated with this WebViewNative!"); 534 535 JNIEnv* env = JSC::Bindings::getJNIEnv(); 536 AutoJObject javaObject = m_javaGlue.object(env); 537 if (!javaObject.get()) 538 return; 539 m_viewImpl->m_touchGeneration = ++m_generation; 540 env->CallVoidMethod(javaObject.get(), m_javaGlue.m_sendMotionUp, m_generation, (jint) framePtr, (jint) nodePtr, x, y); 541 checkException(env); 542} 543 544bool scrollBy(int dx, int dy) 545{ 546 ALOG_ASSERT(m_javaGlue.m_obj, "A java object was not associated with this native WebView!"); 547 548 JNIEnv* env = JSC::Bindings::getJNIEnv(); 549 AutoJObject javaObject = m_javaGlue.object(env); 550 if (!javaObject.get()) 551 return false; 552 bool result = env->CallBooleanMethod(javaObject.get(), m_javaGlue.m_scrollBy, dx, dy, true); 553 checkException(env); 554 return result; 555} 556 557void setIsScrolling(bool isScrolling) 558{ 559#if USE(ACCELERATED_COMPOSITING) 560 if (m_glWebViewState) 561 m_glWebViewState->setIsScrolling(isScrolling); 562#endif 563} 564 565void rebuildWebTextView() 566{ 567 JNIEnv* env = JSC::Bindings::getJNIEnv(); 568 AutoJObject javaObject = m_javaGlue.object(env); 569 if (!javaObject.get()) 570 return; 571 env->CallVoidMethod(javaObject.get(), m_javaGlue.m_rebuildWebTextView); 572 checkException(env); 573} 574 575void viewInvalidate() 576{ 577 JNIEnv* env = JSC::Bindings::getJNIEnv(); 578 AutoJObject javaObject = m_javaGlue.object(env); 579 if (!javaObject.get()) 580 return; 581 env->CallVoidMethod(javaObject.get(), m_javaGlue.m_viewInvalidate); 582 checkException(env); 583} 584 585void viewInvalidateRect(int l, int t, int r, int b) 586{ 587 JNIEnv* env = JSC::Bindings::getJNIEnv(); 588 AutoJObject javaObject = m_javaGlue.object(env); 589 if (!javaObject.get()) 590 return; 591 env->CallVoidMethod(javaObject.get(), m_javaGlue.m_viewInvalidateRect, l, r, t, b); 592 checkException(env); 593} 594 595void postInvalidateDelayed(int64_t delay, const WebCore::IntRect& bounds) 596{ 597 JNIEnv* env = JSC::Bindings::getJNIEnv(); 598 AutoJObject javaObject = m_javaGlue.object(env); 599 if (!javaObject.get()) 600 return; 601 env->CallVoidMethod(javaObject.get(), m_javaGlue.m_postInvalidateDelayed, 602 delay, bounds.x(), bounds.y(), bounds.maxX(), bounds.maxY()); 603 checkException(env); 604} 605 606int moveGeneration() 607{ 608 return m_viewImpl->m_moveGeneration; 609} 610 611LayerAndroid* compositeRoot() const 612{ 613 ALOG_ASSERT(!m_baseLayer || m_baseLayer->countChildren() == 1, 614 "base layer can't have more than one child %s", __FUNCTION__); 615 if (m_baseLayer && m_baseLayer->countChildren() == 1) 616 return static_cast<LayerAndroid*>(m_baseLayer->getChild(0)); 617 else 618 return 0; 619} 620 621#if ENABLE(ANDROID_OVERFLOW_SCROLL) 622static void copyScrollPositionRecursive(const LayerAndroid* from, 623 LayerAndroid* root) 624{ 625 if (!from || !root) 626 return; 627 for (int i = 0; i < from->countChildren(); i++) { 628 const LayerAndroid* l = from->getChild(i); 629 if (l->contentIsScrollable()) { 630 const SkPoint& pos = l->getPosition(); 631 LayerAndroid* match = root->findById(l->uniqueId()); 632 if (match && match->contentIsScrollable()) 633 match->setPosition(pos.fX, pos.fY); 634 } 635 copyScrollPositionRecursive(l, root); 636 } 637} 638#endif 639 640bool setBaseLayer(BaseLayerAndroid* layer, SkRegion& inval, bool showVisualIndicator, 641 bool isPictureAfterFirstLayout) 642{ 643 bool queueFull = false; 644#if USE(ACCELERATED_COMPOSITING) 645 if (m_glWebViewState) { 646 if (layer) 647 layer->markAsDirty(inval); 648 queueFull = m_glWebViewState->setBaseLayer(layer, showVisualIndicator, 649 isPictureAfterFirstLayout); 650 } 651#endif 652 653#if ENABLE(ANDROID_OVERFLOW_SCROLL) 654 if (layer) { 655 // TODO: the below tree copies are only necessary in software rendering 656 LayerAndroid* newCompositeRoot = static_cast<LayerAndroid*>(layer->getChild(0)); 657 copyScrollPositionRecursive(compositeRoot(), newCompositeRoot); 658 } 659#endif 660 SkSafeUnref(m_baseLayer); 661 m_baseLayer = layer; 662 663 return queueFull; 664} 665 666void replaceBaseContent(PictureSet* set) 667{ 668 if (!m_baseLayer) 669 return; 670 m_baseLayer->setContent(*set); 671 delete set; 672} 673 674void copyBaseContentToPicture(SkPicture* picture) 675{ 676 if (!m_baseLayer) 677 return; 678 PictureSet* content = m_baseLayer->content(); 679 m_baseLayer->drawCanvas(picture->beginRecording(content->width(), content->height(), 680 SkPicture::kUsePathBoundsForClip_RecordingFlag)); 681 picture->endRecording(); 682} 683 684bool hasContent() { 685 if (!m_baseLayer) 686 return false; 687 return !m_baseLayer->content()->isEmpty(); 688} 689 690void setFunctor(Functor* functor) { 691 delete m_glDrawFunctor; 692 m_glDrawFunctor = functor; 693} 694 695Functor* getFunctor() { 696 return m_glDrawFunctor; 697} 698 699BaseLayerAndroid* getBaseLayer() { 700 return m_baseLayer; 701} 702 703void setVisibleRect(SkRect& visibleRect) { 704 m_visibleRect = visibleRect; 705} 706 707void setDrawExtra(DrawExtra *extra, DrawExtras type) 708{ 709 if (type == DrawExtrasNone) 710 return; 711 DrawExtra* old = m_extras[type - 1]; 712 m_extras[type - 1] = extra; 713 if (old != extra) { 714 delete old; 715 } 716} 717 718void setTextSelection(SelectText *selection) { 719 setDrawExtra(selection, DrawExtrasSelection); 720} 721 722int getHandleLayerId(SelectText::HandleId handleId, SkIRect& cursorRect) { 723 SelectText* selectText = static_cast<SelectText*>(getDrawExtra(DrawExtrasSelection)); 724 if (!selectText || !m_baseLayer) 725 return -1; 726 int layerId = selectText->caretLayerId(handleId); 727 IntRect rect = selectText->caretRect(handleId); 728 if (layerId != -1) { 729 // We need to make sure the drawTransform is up to date as this is 730 // called before a draw() or drawGL() 731 m_baseLayer->updateLayerPositions(m_visibleRect); 732 LayerAndroid* root = compositeRoot(); 733 LayerAndroid* layer = root ? root->findById(layerId) : 0; 734 if (layer && layer->drawTransform()) 735 rect = layer->drawTransform()->mapRect(rect); 736 } 737 cursorRect.set(rect.x(), rect.y(), rect.maxX(), rect.maxY()); 738 return layerId; 739} 740 741 bool m_isDrawingPaused; 742private: // local state for WebView 743 // private to getFrameCache(); other functions operate in a different thread 744 WebViewCore* m_viewImpl; 745 int m_generation; // associate unique ID with sent kit focus to match with ui 746 // Corresponds to the same-named boolean on the java side. 747 bool m_heightCanMeasure; 748 int m_lastDx; 749 SkMSec m_lastDxTime; 750 DrawExtra* m_extras[DRAW_EXTRAS_SIZE]; 751 BaseLayerAndroid* m_baseLayer; 752 Functor* m_glDrawFunctor; 753#if USE(ACCELERATED_COMPOSITING) 754 GLWebViewState* m_glWebViewState; 755#endif 756 SkRect m_visibleRect; 757 bool m_isHighEndGfx; 758}; // end of WebView class 759 760 761/** 762 * This class holds a function pointer and parameters for calling drawGL into a specific 763 * viewport. The pointer to the Functor will be put on a framework display list to be called 764 * when the display list is replayed. 765 */ 766class GLDrawFunctor : Functor { 767 public: 768 GLDrawFunctor(WebView* _wvInstance, 769 bool(WebView::*_funcPtr)(WebCore::IntRect&, WebCore::IntRect*, 770 WebCore::IntRect&, int, WebCore::IntRect&, jfloat, jint), 771 WebCore::IntRect _viewRect, float _scale, int _extras) { 772 wvInstance = _wvInstance; 773 funcPtr = _funcPtr; 774 viewRect = _viewRect; 775 scale = _scale; 776 extras = _extras; 777 }; 778 status_t operator()(int messageId, void* data) { 779 if (viewRect.isEmpty()) { 780 // NOOP operation if viewport is empty 781 return 0; 782 } 783 784 WebCore::IntRect inval; 785 int titlebarHeight = webViewRect.height() - viewRect.height(); 786 787 uirenderer::DrawGlInfo* info = reinterpret_cast<uirenderer::DrawGlInfo*>(data); 788 WebCore::IntRect localViewRect = viewRect; 789 if (info->isLayer) 790 localViewRect.move(-1 * localViewRect.x(), -1 * localViewRect.y()); 791 792 WebCore::IntRect clip(info->clipLeft, info->clipTop, 793 info->clipRight - info->clipLeft, 794 info->clipBottom - info->clipTop); 795 TilesManager::instance()->shader()->setWebViewMatrix(info->transform, info->isLayer); 796 797 bool retVal = (*wvInstance.*funcPtr)(localViewRect, &inval, webViewRect, 798 titlebarHeight, clip, scale, extras); 799 if (retVal) { 800 IntRect finalInval; 801 if (inval.isEmpty()) { 802 finalInval = webViewRect; 803 retVal = true; 804 } else { 805 finalInval.setX(webViewRect.x() + inval.x()); 806 finalInval.setY(webViewRect.y() + titlebarHeight + inval.y()); 807 finalInval.setWidth(inval.width()); 808 finalInval.setHeight(inval.height()); 809 } 810 info->dirtyLeft = finalInval.x(); 811 info->dirtyTop = finalInval.y(); 812 info->dirtyRight = finalInval.maxX(); 813 info->dirtyBottom = finalInval.maxY(); 814 } 815 // return 1 if invalidation needed, 0 otherwise 816 return retVal ? 1 : 0; 817 } 818 void updateRect(WebCore::IntRect& _viewRect) { 819 viewRect = _viewRect; 820 } 821 void updateViewRect(WebCore::IntRect& _viewRect) { 822 webViewRect = _viewRect; 823 } 824 void updateScale(float _scale) { 825 scale = _scale; 826 } 827 private: 828 WebView* wvInstance; 829 bool (WebView::*funcPtr)(WebCore::IntRect&, WebCore::IntRect*, 830 WebCore::IntRect&, int, WebCore::IntRect&, float, int); 831 WebCore::IntRect viewRect; 832 WebCore::IntRect webViewRect; 833 jfloat scale; 834 jint extras; 835}; 836 837/* 838 * Native JNI methods 839 */ 840static int nativeCacheHitFramePointer(JNIEnv *env, jobject obj) 841{ 842 return 0; 843} 844 845static jobject nativeCacheHitNodeBounds(JNIEnv *env, jobject obj) 846{ 847 return 0; 848} 849 850static int nativeCacheHitNodePointer(JNIEnv *env, jobject obj) 851{ 852 return 0; 853} 854 855static bool nativeCacheHitIsPlugin(JNIEnv *env, jobject obj) 856{ 857 return false; 858} 859 860static void nativeClearCursor(JNIEnv *env, jobject obj) 861{ 862} 863 864static void nativeCreate(JNIEnv *env, jobject obj, int viewImpl, 865 jstring drawableDir, jboolean isHighEndGfx) 866{ 867 WTF::String dir = jstringToWtfString(env, drawableDir); 868 new WebView(env, obj, viewImpl, dir, isHighEndGfx); 869 // NEED THIS OR SOMETHING LIKE IT! 870 //Release(obj); 871} 872 873static jint nativeCursorFramePointer(JNIEnv *env, jobject obj) 874{ 875 return 0; 876} 877 878static bool focusCandidateHasNextTextfield(JNIEnv *env, jobject obj) 879{ 880 return false; 881} 882 883static jboolean nativePageShouldHandleShiftAndArrows(JNIEnv *env, jobject obj) 884{ 885 return true; 886} 887 888static jobject nativeCursorNodeBounds(JNIEnv *env, jobject obj) 889{ 890 return 0; 891} 892 893static jint nativeCursorNodePointer(JNIEnv *env, jobject obj) 894{ 895 return 0; 896} 897 898static jobject nativeCursorPosition(JNIEnv *env, jobject obj) 899{ 900 return 0; 901} 902 903static WebCore::IntRect jrect_to_webrect(JNIEnv* env, jobject obj) 904{ 905 if (obj) { 906 int L, T, R, B; 907 GraphicsJNI::get_jrect(env, obj, &L, &T, &R, &B); 908 return WebCore::IntRect(L, T, R - L, B - T); 909 } else 910 return WebCore::IntRect(); 911} 912 913static SkRect jrectf_to_rect(JNIEnv* env, jobject obj) 914{ 915 SkRect rect = SkRect::MakeEmpty(); 916 if (obj) 917 GraphicsJNI::jrectf_to_rect(env, obj, &rect); 918 return rect; 919} 920 921static bool nativeCursorIntersects(JNIEnv *env, jobject obj, jobject visRect) 922{ 923 return false; 924} 925 926static bool nativeCursorIsAnchor(JNIEnv *env, jobject obj) 927{ 928 return false; 929} 930 931static bool nativeCursorIsTextInput(JNIEnv *env, jobject obj) 932{ 933 return false; 934} 935 936static jobject nativeCursorText(JNIEnv *env, jobject obj) 937{ 938 return 0; 939} 940 941static void nativeDebugDump(JNIEnv *env, jobject obj) 942{ 943} 944 945static jint nativeDraw(JNIEnv *env, jobject obj, jobject canv, 946 jobject visible, jint color, 947 jint extras, jboolean split) { 948 SkCanvas* canvas = GraphicsJNI::getNativeCanvas(env, canv); 949 WebView* webView = GET_NATIVE_VIEW(env, obj); 950 SkRect visibleRect = jrectf_to_rect(env, visible); 951 webView->setVisibleRect(visibleRect); 952 PictureSet* pictureSet = webView->draw(canvas, color, 953 static_cast<WebView::DrawExtras>(extras), split); 954 return reinterpret_cast<jint>(pictureSet); 955} 956 957static jint nativeGetDrawGLFunction(JNIEnv *env, jobject obj, jint nativeView, 958 jobject jrect, jobject jviewrect, 959 jobject jvisiblerect, 960 jfloat scale, jint extras) { 961 WebCore::IntRect viewRect = jrect_to_webrect(env, jrect); 962 WebView *wvInstance = (WebView*) nativeView; 963 SkRect visibleRect = jrectf_to_rect(env, jvisiblerect); 964 wvInstance->setVisibleRect(visibleRect); 965 966 GLDrawFunctor* functor = new GLDrawFunctor(wvInstance, 967 &android::WebView::drawGL, viewRect, scale, extras); 968 wvInstance->setFunctor((Functor*) functor); 969 970 WebCore::IntRect webViewRect = jrect_to_webrect(env, jviewrect); 971 functor->updateViewRect(webViewRect); 972 973 return (jint)functor; 974} 975 976static void nativeUpdateDrawGLFunction(JNIEnv *env, jobject obj, jobject jrect, 977 jobject jviewrect, jobject jvisiblerect, jfloat scale) { 978 WebView *wvInstance = GET_NATIVE_VIEW(env, obj); 979 if (wvInstance) { 980 GLDrawFunctor* functor = (GLDrawFunctor*) wvInstance->getFunctor(); 981 if (functor) { 982 WebCore::IntRect viewRect = jrect_to_webrect(env, jrect); 983 functor->updateRect(viewRect); 984 985 SkRect visibleRect = jrectf_to_rect(env, jvisiblerect); 986 wvInstance->setVisibleRect(visibleRect); 987 988 WebCore::IntRect webViewRect = jrect_to_webrect(env, jviewrect); 989 functor->updateViewRect(webViewRect); 990 991 functor->updateScale(scale); 992 } 993 } 994} 995 996static bool nativeEvaluateLayersAnimations(JNIEnv *env, jobject obj, jint nativeView) 997{ 998 // only call in software rendering, initialize and evaluate animations 999#if USE(ACCELERATED_COMPOSITING) 1000 LayerAndroid* root = ((WebView*)nativeView)->compositeRoot(); 1001 if (root) { 1002 root->initAnimations(); 1003 return root->evaluateAnimations(); 1004 } 1005#endif 1006 return false; 1007} 1008 1009static bool nativeSetBaseLayer(JNIEnv *env, jobject obj, jint nativeView, jint layer, jobject inval, 1010 jboolean showVisualIndicator, 1011 jboolean isPictureAfterFirstLayout) 1012{ 1013 BaseLayerAndroid* layerImpl = reinterpret_cast<BaseLayerAndroid*>(layer); 1014 SkRegion invalRegion; 1015 if (inval) 1016 invalRegion = *GraphicsJNI::getNativeRegion(env, inval); 1017 return ((WebView*)nativeView)->setBaseLayer(layerImpl, invalRegion, showVisualIndicator, 1018 isPictureAfterFirstLayout); 1019} 1020 1021static BaseLayerAndroid* nativeGetBaseLayer(JNIEnv *env, jobject obj) 1022{ 1023 return GET_NATIVE_VIEW(env, obj)->getBaseLayer(); 1024} 1025 1026static void nativeReplaceBaseContent(JNIEnv *env, jobject obj, jint content) 1027{ 1028 PictureSet* set = reinterpret_cast<PictureSet*>(content); 1029 GET_NATIVE_VIEW(env, obj)->replaceBaseContent(set); 1030} 1031 1032static void nativeCopyBaseContentToPicture(JNIEnv *env, jobject obj, jobject pict) 1033{ 1034 SkPicture* picture = GraphicsJNI::getNativePicture(env, pict); 1035 GET_NATIVE_VIEW(env, obj)->copyBaseContentToPicture(picture); 1036} 1037 1038static bool nativeHasContent(JNIEnv *env, jobject obj) 1039{ 1040 return GET_NATIVE_VIEW(env, obj)->hasContent(); 1041} 1042 1043static jobject nativeImageURI(JNIEnv *env, jobject obj, jint x, jint y) 1044{ 1045 return 0; 1046} 1047 1048static jint nativeFocusCandidateFramePointer(JNIEnv *env, jobject obj) 1049{ 1050 return 0; 1051} 1052 1053static bool nativeFocusCandidateIsEditableText(JNIEnv* env, jobject obj, 1054 jint nativeClass) 1055{ 1056 return false; 1057} 1058 1059static bool nativeFocusCandidateIsPassword(JNIEnv *env, jobject obj) 1060{ 1061 return false; 1062} 1063 1064static bool nativeFocusCandidateIsRtlText(JNIEnv *env, jobject obj) 1065{ 1066 return false; 1067} 1068 1069static bool nativeFocusCandidateIsTextInput(JNIEnv *env, jobject obj) 1070{ 1071 return false; 1072} 1073 1074static jint nativeFocusCandidateMaxLength(JNIEnv *env, jobject obj) 1075{ 1076 return 0; 1077} 1078 1079static jint nativeFocusCandidateIsAutoComplete(JNIEnv *env, jobject obj) 1080{ 1081 return 0; 1082} 1083 1084static jobject nativeFocusCandidateName(JNIEnv *env, jobject obj) 1085{ 1086 return false; 1087} 1088 1089static jobject nativeFocusCandidateNodeBounds(JNIEnv *env, jobject obj) 1090{ 1091 return 0; 1092} 1093 1094static jobject nativeFocusCandidatePaddingRect(JNIEnv *env, jobject obj) 1095{ 1096 return 0; 1097} 1098 1099static jint nativeFocusCandidatePointer(JNIEnv *env, jobject obj) 1100{ 1101 return 0; 1102} 1103 1104static jint nativeFocusCandidateIsSpellcheck(JNIEnv *env, jobject obj) 1105{ 1106 return 0; 1107} 1108 1109static jobject nativeFocusCandidateText(JNIEnv *env, jobject obj) 1110{ 1111 return 0; 1112} 1113 1114static int nativeFocusCandidateLineHeight(JNIEnv *env, jobject obj) 1115{ 1116 return 0; 1117} 1118 1119static jfloat nativeFocusCandidateTextSize(JNIEnv *env, jobject obj) 1120{ 1121 return 0.f; 1122} 1123 1124static int nativeFocusCandidateType(JNIEnv *env, jobject obj) 1125{ 1126 return 0; 1127} 1128 1129static int nativeFocusCandidateLayerId(JNIEnv *env, jobject obj) 1130{ 1131 return 0; 1132} 1133 1134static bool nativeFocusIsPlugin(JNIEnv *env, jobject obj) 1135{ 1136 return false; 1137} 1138 1139static jobject nativeFocusNodeBounds(JNIEnv *env, jobject obj) 1140{ 1141 return 0; 1142} 1143 1144static jint nativeFocusNodePointer(JNIEnv *env, jobject obj) 1145{ 1146 return 0; 1147} 1148 1149static bool nativeCursorWantsKeyEvents(JNIEnv* env, jobject jwebview) { 1150 return false; 1151} 1152 1153static void nativeHideCursor(JNIEnv *env, jobject obj) 1154{ 1155} 1156 1157static void nativeSelectBestAt(JNIEnv *env, jobject obj, jobject jrect) 1158{ 1159} 1160 1161static void nativeSelectAt(JNIEnv *env, jobject obj, jint x, jint y) 1162{ 1163} 1164 1165static jobject nativeLayerBounds(JNIEnv* env, jobject obj, jint jlayer) 1166{ 1167 SkRect r; 1168#if USE(ACCELERATED_COMPOSITING) 1169 LayerAndroid* layer = (LayerAndroid*) jlayer; 1170 r = layer->bounds(); 1171#else 1172 r.setEmpty(); 1173#endif 1174 SkIRect irect; 1175 r.round(&irect); 1176 jclass rectClass = env->FindClass("android/graphics/Rect"); 1177 jmethodID init = env->GetMethodID(rectClass, "<init>", "(IIII)V"); 1178 jobject rect = env->NewObject(rectClass, init, irect.fLeft, irect.fTop, 1179 irect.fRight, irect.fBottom); 1180 env->DeleteLocalRef(rectClass); 1181 return rect; 1182} 1183 1184static jobject nativeSubtractLayers(JNIEnv* env, jobject obj, jobject jrect) 1185{ 1186 SkIRect irect = jrect_to_webrect(env, jrect); 1187#if USE(ACCELERATED_COMPOSITING) 1188 LayerAndroid* root = GET_NATIVE_VIEW(env, obj)->compositeRoot(); 1189 if (root) { 1190 SkRect rect; 1191 rect.set(irect); 1192 rect = root->subtractLayers(rect); 1193 rect.round(&irect); 1194 } 1195#endif 1196 jclass rectClass = env->FindClass("android/graphics/Rect"); 1197 jmethodID init = env->GetMethodID(rectClass, "<init>", "(IIII)V"); 1198 jobject rect = env->NewObject(rectClass, init, irect.fLeft, irect.fTop, 1199 irect.fRight, irect.fBottom); 1200 env->DeleteLocalRef(rectClass); 1201 return rect; 1202} 1203 1204static jint nativeTextGeneration(JNIEnv *env, jobject obj) 1205{ 1206 return 0; 1207} 1208 1209static bool nativePointInNavCache(JNIEnv *env, jobject obj, 1210 int x, int y, int slop) 1211{ 1212 return false; 1213} 1214 1215static bool nativeMotionUp(JNIEnv *env, jobject obj, 1216 int x, int y, int slop) 1217{ 1218 return false; 1219} 1220 1221static bool nativeHasCursorNode(JNIEnv *env, jobject obj) 1222{ 1223 return false; 1224} 1225 1226static bool nativeHasFocusNode(JNIEnv *env, jobject obj) 1227{ 1228 return false; 1229} 1230 1231static bool nativeMoveCursor(JNIEnv *env, jobject obj, 1232 int key, int count, bool ignoreScroll) 1233{ 1234 return false; 1235} 1236 1237static void nativeSetFindIsUp(JNIEnv *env, jobject obj, jboolean isUp) 1238{ 1239 WebView* view = GET_NATIVE_VIEW(env, obj); 1240 ALOG_ASSERT(view, "view not set in %s", __FUNCTION__); 1241 view->setFindIsUp(isUp); 1242} 1243 1244static void nativeShowCursorTimed(JNIEnv *env, jobject obj) 1245{ 1246} 1247 1248static void nativeSetHeightCanMeasure(JNIEnv *env, jobject obj, bool measure) 1249{ 1250 WebView* view = GET_NATIVE_VIEW(env, obj); 1251 ALOG_ASSERT(view, "view not set in nativeSetHeightCanMeasure"); 1252 view->setHeightCanMeasure(measure); 1253} 1254 1255static jobject nativeGetCursorRingBounds(JNIEnv *env, jobject obj) 1256{ 1257 return 0; 1258} 1259 1260static void nativeUpdateCachedTextfield(JNIEnv *env, jobject obj, jstring updatedText, jint generation) 1261{ 1262} 1263 1264static jint nativeGetBlockLeftEdge(JNIEnv *env, jobject obj, jint x, jint y, 1265 jfloat scale) 1266{ 1267 return -1; 1268} 1269 1270static void nativeDestroy(JNIEnv *env, jobject obj) 1271{ 1272 WebView* view = GET_NATIVE_VIEW(env, obj); 1273 ALOGD("nativeDestroy view: %p", view); 1274 ALOG_ASSERT(view, "view not set in nativeDestroy"); 1275 delete view; 1276} 1277 1278static void nativeStopGL(JNIEnv *env, jobject obj) 1279{ 1280 GET_NATIVE_VIEW(env, obj)->stopGL(); 1281} 1282 1283static bool nativeMoveCursorToNextTextInput(JNIEnv *env, jobject obj) 1284{ 1285 return false; 1286} 1287 1288static int nativeMoveGeneration(JNIEnv *env, jobject obj) 1289{ 1290 WebView* view = GET_NATIVE_VIEW(env, obj); 1291 if (!view) 1292 return 0; 1293 return view->moveGeneration(); 1294} 1295 1296static jobject nativeGetSelection(JNIEnv *env, jobject obj) 1297{ 1298 WebView* view = GET_NATIVE_VIEW(env, obj); 1299 ALOG_ASSERT(view, "view not set in %s", __FUNCTION__); 1300 String selection = view->getSelection(); 1301 return wtfStringToJstring(env, selection); 1302} 1303 1304static void nativeDiscardAllTextures(JNIEnv *env, jobject obj) 1305{ 1306 //discard all textures for debugging/test purposes, but not gl backing memory 1307 bool allTextures = true, deleteGLTextures = false; 1308 TilesManager::instance()->discardTextures(allTextures, deleteGLTextures); 1309} 1310 1311static void nativeTileProfilingStart(JNIEnv *env, jobject obj) 1312{ 1313 TilesManager::instance()->getProfiler()->start(); 1314} 1315 1316static float nativeTileProfilingStop(JNIEnv *env, jobject obj) 1317{ 1318 return TilesManager::instance()->getProfiler()->stop(); 1319} 1320 1321static void nativeTileProfilingClear(JNIEnv *env, jobject obj) 1322{ 1323 TilesManager::instance()->getProfiler()->clear(); 1324} 1325 1326static int nativeTileProfilingNumFrames(JNIEnv *env, jobject obj) 1327{ 1328 return TilesManager::instance()->getProfiler()->numFrames(); 1329} 1330 1331static int nativeTileProfilingNumTilesInFrame(JNIEnv *env, jobject obj, int frame) 1332{ 1333 return TilesManager::instance()->getProfiler()->numTilesInFrame(frame); 1334} 1335 1336static int nativeTileProfilingGetInt(JNIEnv *env, jobject obj, int frame, int tile, jstring jkey) 1337{ 1338 WTF::String key = jstringToWtfString(env, jkey); 1339 TileProfileRecord* record = TilesManager::instance()->getProfiler()->getTile(frame, tile); 1340 1341 if (key == "left") 1342 return record->left; 1343 if (key == "top") 1344 return record->top; 1345 if (key == "right") 1346 return record->right; 1347 if (key == "bottom") 1348 return record->bottom; 1349 if (key == "level") 1350 return record->level; 1351 if (key == "isReady") 1352 return record->isReady ? 1 : 0; 1353 return -1; 1354} 1355 1356static float nativeTileProfilingGetFloat(JNIEnv *env, jobject obj, int frame, int tile, jstring jkey) 1357{ 1358 TileProfileRecord* record = TilesManager::instance()->getProfiler()->getTile(frame, tile); 1359 return record->scale; 1360} 1361 1362#ifdef ANDROID_DUMP_DISPLAY_TREE 1363static void dumpToFile(const char text[], void* file) { 1364 fwrite(text, 1, strlen(text), reinterpret_cast<FILE*>(file)); 1365 fwrite("\n", 1, 1, reinterpret_cast<FILE*>(file)); 1366} 1367#endif 1368 1369static bool nativeSetProperty(JNIEnv *env, jobject obj, jstring jkey, jstring jvalue) 1370{ 1371 WTF::String key = jstringToWtfString(env, jkey); 1372 WTF::String value = jstringToWtfString(env, jvalue); 1373 if (key == "inverted") { 1374 bool shouldInvert = (value == "true"); 1375 TilesManager::instance()->setInvertedScreen(shouldInvert); 1376 return true; 1377 } 1378 else if (key == "inverted_contrast") { 1379 float contrast = value.toFloat(); 1380 TilesManager::instance()->setInvertedScreenContrast(contrast); 1381 return true; 1382 } 1383 else if (key == "enable_cpu_upload_path") { 1384 TilesManager::instance()->transferQueue()->setTextureUploadType( 1385 value == "true" ? CpuUpload : GpuUpload); 1386 return true; 1387 } 1388 else if (key == "use_minimal_memory") { 1389 TilesManager::instance()->setUseMinimalMemory(value == "true"); 1390 return true; 1391 } 1392 else if (key == "use_double_buffering") { 1393 TilesManager::instance()->setUseDoubleBuffering(value == "true"); 1394 return true; 1395 } 1396 else if (key == "tree_updates") { 1397 TilesManager::instance()->clearContentUpdates(); 1398 return true; 1399 } 1400 return false; 1401} 1402 1403static jstring nativeGetProperty(JNIEnv *env, jobject obj, jstring jkey) 1404{ 1405 WTF::String key = jstringToWtfString(env, jkey); 1406 if (key == "tree_updates") { 1407 int updates = TilesManager::instance()->getContentUpdates(); 1408 WTF::String wtfUpdates = WTF::String::number(updates); 1409 return wtfStringToJstring(env, wtfUpdates); 1410 } 1411 return 0; 1412} 1413 1414static void nativeOnTrimMemory(JNIEnv *env, jobject obj, jint level) 1415{ 1416 if (TilesManager::hardwareAccelerationEnabled()) { 1417 // When we got TRIM_MEMORY_MODERATE or TRIM_MEMORY_COMPLETE, we should 1418 // make sure the transfer queue is empty and then abandon the Surface 1419 // Texture to avoid ANR b/c framework may destroy the EGL context. 1420 // Refer to WindowManagerImpl.java for conditions we followed. 1421 TilesManager* tilesManager = TilesManager::instance(); 1422 if (level >= TRIM_MEMORY_MODERATE 1423 && !tilesManager->highEndGfx()) { 1424 ALOGD("OnTrimMemory with EGL Context %p", eglGetCurrentContext()); 1425 tilesManager->transferQueue()->emptyQueue(); 1426 tilesManager->shader()->cleanupGLResources(); 1427 tilesManager->videoLayerManager()->cleanupGLResources(); 1428 } 1429 1430 bool freeAllTextures = (level > TRIM_MEMORY_UI_HIDDEN), glTextures = true; 1431 tilesManager->discardTextures(freeAllTextures, glTextures); 1432 } 1433} 1434 1435static void nativeDumpDisplayTree(JNIEnv* env, jobject jwebview, jstring jurl) 1436{ 1437#ifdef ANDROID_DUMP_DISPLAY_TREE 1438 WebView* view = GET_NATIVE_VIEW(env, jwebview); 1439 ALOG_ASSERT(view, "view not set in %s", __FUNCTION__); 1440 1441 if (view && view->getWebViewCore()) { 1442 FILE* file = fopen(DISPLAY_TREE_LOG_FILE, "w"); 1443 if (file) { 1444 SkFormatDumper dumper(dumpToFile, file); 1445 // dump the URL 1446 if (jurl) { 1447 const char* str = env->GetStringUTFChars(jurl, 0); 1448 SkDebugf("Dumping %s to %s\n", str, DISPLAY_TREE_LOG_FILE); 1449 dumpToFile(str, file); 1450 env->ReleaseStringUTFChars(jurl, str); 1451 } 1452 // now dump the display tree 1453 SkDumpCanvas canvas(&dumper); 1454 // this will playback the picture into the canvas, which will 1455 // spew its contents to the dumper 1456 view->draw(&canvas, 0, WebView::DrawExtrasNone, false); 1457 // we're done with the file now 1458 fwrite("\n", 1, 1, file); 1459 fclose(file); 1460 } 1461#if USE(ACCELERATED_COMPOSITING) 1462 const LayerAndroid* rootLayer = view->compositeRoot(); 1463 if (rootLayer) { 1464 FILE* file = fopen(LAYERS_TREE_LOG_FILE,"w"); 1465 if (file) { 1466 rootLayer->dumpLayers(file, 0); 1467 fclose(file); 1468 } 1469 } 1470#endif 1471 } 1472#endif 1473} 1474 1475static int nativeScrollableLayer(JNIEnv* env, jobject jwebview, jint x, jint y, 1476 jobject rect, jobject bounds) 1477{ 1478 WebView* view = GET_NATIVE_VIEW(env, jwebview); 1479 ALOG_ASSERT(view, "view not set in %s", __FUNCTION__); 1480 SkIRect nativeRect, nativeBounds; 1481 int id = view->scrollableLayer(x, y, &nativeRect, &nativeBounds); 1482 if (rect) 1483 GraphicsJNI::irect_to_jrect(nativeRect, env, rect); 1484 if (bounds) 1485 GraphicsJNI::irect_to_jrect(nativeBounds, env, bounds); 1486 return id; 1487} 1488 1489static bool nativeScrollLayer(JNIEnv* env, jobject obj, jint layerId, jint x, 1490 jint y) 1491{ 1492#if ENABLE(ANDROID_OVERFLOW_SCROLL) 1493 WebView* view = GET_NATIVE_VIEW(env, obj); 1494 view->scrollLayer(layerId, x, y); 1495 1496 //TODO: the below only needed for the SW rendering path 1497 LayerAndroid* root = view->compositeRoot(); 1498 if (!root) 1499 return false; 1500 LayerAndroid* layer = root->findById(layerId); 1501 if (!layer || !layer->contentIsScrollable()) 1502 return false; 1503 return static_cast<ScrollableLayerAndroid*>(layer)->scrollTo(x, y); 1504#endif 1505 return false; 1506} 1507 1508static void nativeSetIsScrolling(JNIEnv* env, jobject jwebview, jboolean isScrolling) 1509{ 1510 WebView* view = GET_NATIVE_VIEW(env, jwebview); 1511 ALOG_ASSERT(view, "view not set in %s", __FUNCTION__); 1512 view->setIsScrolling(isScrolling); 1513} 1514 1515static void nativeUseHardwareAccelSkia(JNIEnv*, jobject, jboolean enabled) 1516{ 1517 BaseRenderer::setCurrentRendererType(enabled ? BaseRenderer::Ganesh : BaseRenderer::Raster); 1518} 1519 1520static int nativeGetBackgroundColor(JNIEnv* env, jobject obj) 1521{ 1522 WebView* view = GET_NATIVE_VIEW(env, obj); 1523 BaseLayerAndroid* baseLayer = view->getBaseLayer(); 1524 if (baseLayer) { 1525 WebCore::Color color = baseLayer->getBackgroundColor(); 1526 if (color.isValid()) 1527 return SkColorSetARGB(color.alpha(), color.red(), 1528 color.green(), color.blue()); 1529 } 1530 return SK_ColorWHITE; 1531} 1532 1533static void nativeSetPauseDrawing(JNIEnv *env, jobject obj, jint nativeView, 1534 jboolean pause) 1535{ 1536 ((WebView*)nativeView)->m_isDrawingPaused = pause; 1537} 1538 1539static bool nativeDisableNavcache(JNIEnv *env, jobject obj) 1540{ 1541 return true; 1542} 1543 1544static void nativeSetTextSelection(JNIEnv *env, jobject obj, jint nativeView, 1545 jint selectionPtr) 1546{ 1547 SelectText* selection = reinterpret_cast<SelectText*>(selectionPtr); 1548 reinterpret_cast<WebView*>(nativeView)->setTextSelection(selection); 1549} 1550 1551static jint nativeGetHandleLayerId(JNIEnv *env, jobject obj, jint nativeView, 1552 jint handleIndex, jobject cursorRect) 1553{ 1554 WebView* webview = reinterpret_cast<WebView*>(nativeView); 1555 SkIRect nativeRect; 1556 int layerId = webview->getHandleLayerId((SelectText::HandleId) handleIndex, nativeRect); 1557 if (cursorRect) 1558 GraphicsJNI::irect_to_jrect(nativeRect, env, cursorRect); 1559 return layerId; 1560} 1561 1562static jboolean nativeIsBaseFirst(JNIEnv *env, jobject obj, jint nativeView) 1563{ 1564 WebView* webview = reinterpret_cast<WebView*>(nativeView); 1565 SelectText* select = static_cast<SelectText*>( 1566 webview->getDrawExtra(WebView::DrawExtrasSelection)); 1567 return select ? select->isBaseFirst() : false; 1568} 1569 1570/* 1571 * JNI registration 1572 */ 1573static JNINativeMethod gJavaWebViewMethods[] = { 1574 { "nativeCacheHitFramePointer", "()I", 1575 (void*) nativeCacheHitFramePointer }, 1576 { "nativeCacheHitIsPlugin", "()Z", 1577 (void*) nativeCacheHitIsPlugin }, 1578 { "nativeCacheHitNodeBounds", "()Landroid/graphics/Rect;", 1579 (void*) nativeCacheHitNodeBounds }, 1580 { "nativeCacheHitNodePointer", "()I", 1581 (void*) nativeCacheHitNodePointer }, 1582 { "nativeClearCursor", "()V", 1583 (void*) nativeClearCursor }, 1584 { "nativeCreate", "(ILjava/lang/String;Z)V", 1585 (void*) nativeCreate }, 1586 { "nativeCursorFramePointer", "()I", 1587 (void*) nativeCursorFramePointer }, 1588 { "nativePageShouldHandleShiftAndArrows", "()Z", 1589 (void*) nativePageShouldHandleShiftAndArrows }, 1590 { "nativeCursorNodeBounds", "()Landroid/graphics/Rect;", 1591 (void*) nativeCursorNodeBounds }, 1592 { "nativeCursorNodePointer", "()I", 1593 (void*) nativeCursorNodePointer }, 1594 { "nativeCursorIntersects", "(Landroid/graphics/Rect;)Z", 1595 (void*) nativeCursorIntersects }, 1596 { "nativeCursorIsAnchor", "()Z", 1597 (void*) nativeCursorIsAnchor }, 1598 { "nativeCursorIsTextInput", "()Z", 1599 (void*) nativeCursorIsTextInput }, 1600 { "nativeCursorPosition", "()Landroid/graphics/Point;", 1601 (void*) nativeCursorPosition }, 1602 { "nativeCursorText", "()Ljava/lang/String;", 1603 (void*) nativeCursorText }, 1604 { "nativeCursorWantsKeyEvents", "()Z", 1605 (void*)nativeCursorWantsKeyEvents }, 1606 { "nativeDebugDump", "()V", 1607 (void*) nativeDebugDump }, 1608 { "nativeDestroy", "()V", 1609 (void*) nativeDestroy }, 1610 { "nativeDraw", "(Landroid/graphics/Canvas;Landroid/graphics/RectF;IIZ)I", 1611 (void*) nativeDraw }, 1612 { "nativeGetDrawGLFunction", "(ILandroid/graphics/Rect;Landroid/graphics/Rect;Landroid/graphics/RectF;FI)I", 1613 (void*) nativeGetDrawGLFunction }, 1614 { "nativeUpdateDrawGLFunction", "(Landroid/graphics/Rect;Landroid/graphics/Rect;Landroid/graphics/RectF;F)V", 1615 (void*) nativeUpdateDrawGLFunction }, 1616 { "nativeDumpDisplayTree", "(Ljava/lang/String;)V", 1617 (void*) nativeDumpDisplayTree }, 1618 { "nativeEvaluateLayersAnimations", "(I)Z", 1619 (void*) nativeEvaluateLayersAnimations }, 1620 { "nativeFocusCandidateFramePointer", "()I", 1621 (void*) nativeFocusCandidateFramePointer }, 1622 { "nativeFocusCandidateHasNextTextfield", "()Z", 1623 (void*) focusCandidateHasNextTextfield }, 1624 { "nativeFocusCandidateIsPassword", "()Z", 1625 (void*) nativeFocusCandidateIsPassword }, 1626 { "nativeFocusCandidateIsRtlText", "()Z", 1627 (void*) nativeFocusCandidateIsRtlText }, 1628 { "nativeFocusCandidateIsTextInput", "()Z", 1629 (void*) nativeFocusCandidateIsTextInput }, 1630 { "nativeFocusCandidateLineHeight", "()I", 1631 (void*) nativeFocusCandidateLineHeight }, 1632 { "nativeFocusCandidateMaxLength", "()I", 1633 (void*) nativeFocusCandidateMaxLength }, 1634 { "nativeFocusCandidateIsAutoComplete", "()Z", 1635 (void*) nativeFocusCandidateIsAutoComplete }, 1636 { "nativeFocusCandidateIsSpellcheck", "()Z", 1637 (void*) nativeFocusCandidateIsSpellcheck }, 1638 { "nativeFocusCandidateName", "()Ljava/lang/String;", 1639 (void*) nativeFocusCandidateName }, 1640 { "nativeFocusCandidateNodeBounds", "()Landroid/graphics/Rect;", 1641 (void*) nativeFocusCandidateNodeBounds }, 1642 { "nativeFocusCandidatePaddingRect", "()Landroid/graphics/Rect;", 1643 (void*) nativeFocusCandidatePaddingRect }, 1644 { "nativeFocusCandidatePointer", "()I", 1645 (void*) nativeFocusCandidatePointer }, 1646 { "nativeFocusCandidateText", "()Ljava/lang/String;", 1647 (void*) nativeFocusCandidateText }, 1648 { "nativeFocusCandidateTextSize", "()F", 1649 (void*) nativeFocusCandidateTextSize }, 1650 { "nativeFocusCandidateType", "()I", 1651 (void*) nativeFocusCandidateType }, 1652 { "nativeFocusCandidateLayerId", "()I", 1653 (void*) nativeFocusCandidateLayerId }, 1654 { "nativeFocusIsPlugin", "()Z", 1655 (void*) nativeFocusIsPlugin }, 1656 { "nativeFocusNodeBounds", "()Landroid/graphics/Rect;", 1657 (void*) nativeFocusNodeBounds }, 1658 { "nativeFocusNodePointer", "()I", 1659 (void*) nativeFocusNodePointer }, 1660 { "nativeGetCursorRingBounds", "()Landroid/graphics/Rect;", 1661 (void*) nativeGetCursorRingBounds }, 1662 { "nativeGetSelection", "()Ljava/lang/String;", 1663 (void*) nativeGetSelection }, 1664 { "nativeHasCursorNode", "()Z", 1665 (void*) nativeHasCursorNode }, 1666 { "nativeHasFocusNode", "()Z", 1667 (void*) nativeHasFocusNode }, 1668 { "nativeHideCursor", "()V", 1669 (void*) nativeHideCursor }, 1670 { "nativeImageURI", "(II)Ljava/lang/String;", 1671 (void*) nativeImageURI }, 1672 { "nativeLayerBounds", "(I)Landroid/graphics/Rect;", 1673 (void*) nativeLayerBounds }, 1674 { "nativeMotionUp", "(III)Z", 1675 (void*) nativeMotionUp }, 1676 { "nativeMoveCursor", "(IIZ)Z", 1677 (void*) nativeMoveCursor }, 1678 { "nativeMoveCursorToNextTextInput", "()Z", 1679 (void*) nativeMoveCursorToNextTextInput }, 1680 { "nativeMoveGeneration", "()I", 1681 (void*) nativeMoveGeneration }, 1682 { "nativePointInNavCache", "(III)Z", 1683 (void*) nativePointInNavCache }, 1684 { "nativeSelectBestAt", "(Landroid/graphics/Rect;)V", 1685 (void*) nativeSelectBestAt }, 1686 { "nativeSelectAt", "(II)V", 1687 (void*) nativeSelectAt }, 1688 { "nativeSetFindIsUp", "(Z)V", 1689 (void*) nativeSetFindIsUp }, 1690 { "nativeSetHeightCanMeasure", "(Z)V", 1691 (void*) nativeSetHeightCanMeasure }, 1692 { "nativeSetBaseLayer", "(IILandroid/graphics/Region;ZZ)Z", 1693 (void*) nativeSetBaseLayer }, 1694 { "nativeGetBaseLayer", "()I", 1695 (void*) nativeGetBaseLayer }, 1696 { "nativeReplaceBaseContent", "(I)V", 1697 (void*) nativeReplaceBaseContent }, 1698 { "nativeCopyBaseContentToPicture", "(Landroid/graphics/Picture;)V", 1699 (void*) nativeCopyBaseContentToPicture }, 1700 { "nativeHasContent", "()Z", 1701 (void*) nativeHasContent }, 1702 { "nativeShowCursorTimed", "()V", 1703 (void*) nativeShowCursorTimed }, 1704 { "nativeDiscardAllTextures", "()V", 1705 (void*) nativeDiscardAllTextures }, 1706 { "nativeTileProfilingStart", "()V", 1707 (void*) nativeTileProfilingStart }, 1708 { "nativeTileProfilingStop", "()F", 1709 (void*) nativeTileProfilingStop }, 1710 { "nativeTileProfilingClear", "()V", 1711 (void*) nativeTileProfilingClear }, 1712 { "nativeTileProfilingNumFrames", "()I", 1713 (void*) nativeTileProfilingNumFrames }, 1714 { "nativeTileProfilingNumTilesInFrame", "(I)I", 1715 (void*) nativeTileProfilingNumTilesInFrame }, 1716 { "nativeTileProfilingGetInt", "(IILjava/lang/String;)I", 1717 (void*) nativeTileProfilingGetInt }, 1718 { "nativeTileProfilingGetFloat", "(IILjava/lang/String;)F", 1719 (void*) nativeTileProfilingGetFloat }, 1720 { "nativeStopGL", "()V", 1721 (void*) nativeStopGL }, 1722 { "nativeSubtractLayers", "(Landroid/graphics/Rect;)Landroid/graphics/Rect;", 1723 (void*) nativeSubtractLayers }, 1724 { "nativeTextGeneration", "()I", 1725 (void*) nativeTextGeneration }, 1726 { "nativeUpdateCachedTextfield", "(Ljava/lang/String;I)V", 1727 (void*) nativeUpdateCachedTextfield }, 1728 { "nativeGetBlockLeftEdge", "(IIF)I", 1729 (void*) nativeGetBlockLeftEdge }, 1730 { "nativeScrollableLayer", "(IILandroid/graphics/Rect;Landroid/graphics/Rect;)I", 1731 (void*) nativeScrollableLayer }, 1732 { "nativeScrollLayer", "(III)Z", 1733 (void*) nativeScrollLayer }, 1734 { "nativeSetIsScrolling", "(Z)V", 1735 (void*) nativeSetIsScrolling }, 1736 { "nativeUseHardwareAccelSkia", "(Z)V", 1737 (void*) nativeUseHardwareAccelSkia }, 1738 { "nativeGetBackgroundColor", "()I", 1739 (void*) nativeGetBackgroundColor }, 1740 { "nativeSetProperty", "(Ljava/lang/String;Ljava/lang/String;)Z", 1741 (void*) nativeSetProperty }, 1742 { "nativeGetProperty", "(Ljava/lang/String;)Ljava/lang/String;", 1743 (void*) nativeGetProperty }, 1744 { "nativeOnTrimMemory", "(I)V", 1745 (void*) nativeOnTrimMemory }, 1746 { "nativeSetPauseDrawing", "(IZ)V", 1747 (void*) nativeSetPauseDrawing }, 1748 { "nativeDisableNavcache", "()Z", 1749 (void*) nativeDisableNavcache }, 1750 { "nativeFocusCandidateIsEditableText", "(I)Z", 1751 (void*) nativeFocusCandidateIsEditableText }, 1752 { "nativeSetTextSelection", "(II)V", 1753 (void*) nativeSetTextSelection }, 1754 { "nativeGetHandleLayerId", "(IILandroid/graphics/Rect;)I", 1755 (void*) nativeGetHandleLayerId }, 1756 { "nativeIsBaseFirst", "(I)Z", 1757 (void*) nativeIsBaseFirst }, 1758}; 1759 1760int registerWebView(JNIEnv* env) 1761{ 1762 jclass clazz = env->FindClass("android/webkit/WebViewClassic"); 1763 ALOG_ASSERT(clazz, "Unable to find class android/webkit/WebViewClassic"); 1764 gWebViewField = env->GetFieldID(clazz, "mNativeClass", "I"); 1765 ALOG_ASSERT(gWebViewField, "Unable to find android/webkit/WebViewClassic.mNativeClass"); 1766 env->DeleteLocalRef(clazz); 1767 1768 return jniRegisterNativeMethods(env, "android/webkit/WebViewClassic", gJavaWebViewMethods, NELEM(gJavaWebViewMethods)); 1769} 1770 1771} // namespace android 1772