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 "BaseRenderer.h" 34 #include "DrawExtra.h" 35 #include "DumpLayer.h" 36 #include "Frame.h" 37 #include "GLWebViewState.h" 38 #include "GraphicsJNI.h" 39 #include "HTMLInputElement.h" 40 #include "IntPoint.h" 41 #include "IntRect.h" 42 #include "LayerAndroid.h" 43 #include "LayerContent.h" 44 #include "Node.h" 45 #include "utils/Functor.h" 46 #include "private/hwui/DrawGlInfo.h" 47 #include "PlatformGraphicsContext.h" 48 #include "PlatformString.h" 49 #include "ScrollableLayerAndroid.h" 50 #include "SelectText.h" 51 #include "SkCanvas.h" 52 #include "SkDumpCanvas.h" 53 #include "SkPicture.h" 54 #include "SkRect.h" 55 #include "SkTime.h" 56 #include "TilesManager.h" 57 #include "TransferQueue.h" 58 #include "WebCoreJni.h" 59 #include "WebRequestContext.h" 60 #include "WebViewCore.h" 61 62 #ifdef GET_NATIVE_VIEW 63 #undef GET_NATIVE_VIEW 64 #endif 65 66 #define GET_NATIVE_VIEW(env, obj) ((WebView*)env->GetIntField(obj, gWebViewField)) 67 68 #include <JNIUtility.h> 69 #include <JNIHelp.h> 70 #include <jni.h> 71 #include <androidfw/KeycodeLabels.h> 72 #include <wtf/text/AtomicString.h> 73 #include <wtf/text/CString.h> 74 75 // Free as much as we possible can 76 #define TRIM_MEMORY_COMPLETE 80 77 // Free a lot (all textures gone) 78 #define TRIM_MEMORY_MODERATE 60 79 // More moderate free (keep bare minimum to restore quickly-ish - possibly clear all textures) 80 #define TRIM_MEMORY_BACKGROUND 40 81 // Moderate free (clear cached tiles, keep visible ones) 82 #define TRIM_MEMORY_UI_HIDDEN 20 83 // Duration to show the pressed cursor ring 84 #define PRESSED_STATE_DURATION 400 85 86 namespace android { 87 88 static jfieldID gWebViewField; 89 90 //------------------------------------- 91 92 static jmethodID GetJMethod(JNIEnv* env, jclass clazz, const char name[], const char signature[]) 93 { 94 jmethodID m = env->GetMethodID(clazz, name, signature); 95 ALOG_ASSERT(m, "Could not find method %s", name); 96 return m; 97 } 98 99 //------------------------------------- 100 // This class provides JNI for making calls into native code from the UI side 101 // of the multi-threaded WebView. 102 class WebView 103 { 104 public: 105 enum FrameCachePermission { 106 DontAllowNewer, 107 AllowNewer 108 }; 109 110 #define DRAW_EXTRAS_SIZE 2 111 enum DrawExtras { // keep this in sync with WebView.java 112 DrawExtrasNone = 0, 113 DrawExtrasSelection = 1, 114 DrawExtrasCursorRing = 2 115 }; 116 117 struct JavaGlue { 118 jweak m_obj; 119 jmethodID m_scrollBy; 120 jmethodID m_getScaledMaxXScroll; 121 jmethodID m_getScaledMaxYScroll; 122 jmethodID m_updateRectsForGL; 123 jmethodID m_viewInvalidate; 124 jmethodID m_viewInvalidateRect; 125 jmethodID m_postInvalidateDelayed; 126 jmethodID m_pageSwapCallback; 127 jfieldID m_rectLeft; 128 jfieldID m_rectTop; 129 jmethodID m_rectWidth; 130 jmethodID m_rectHeight; 131 jfieldID m_quadFP1; 132 jfieldID m_quadFP2; 133 jfieldID m_quadFP3; 134 jfieldID m_quadFP4; 135 AutoJObject object(JNIEnv* env) { 136 return getRealObject(env, m_obj); 137 } 138 } m_javaGlue; 139 140 WebView(JNIEnv* env, jobject javaWebView, int viewImpl, WTF::String drawableDir, 141 bool isHighEndGfx) 142 : m_isHighEndGfx(isHighEndGfx) 143 { 144 memset(m_extras, 0, DRAW_EXTRAS_SIZE * sizeof(DrawExtra*)); 145 jclass clazz = env->FindClass("android/webkit/WebViewClassic"); 146 m_javaGlue.m_obj = env->NewWeakGlobalRef(javaWebView); 147 m_javaGlue.m_scrollBy = GetJMethod(env, clazz, "setContentScrollBy", "(IIZ)Z"); 148 m_javaGlue.m_getScaledMaxXScroll = GetJMethod(env, clazz, "getScaledMaxXScroll", "()I"); 149 m_javaGlue.m_getScaledMaxYScroll = GetJMethod(env, clazz, "getScaledMaxYScroll", "()I"); 150 m_javaGlue.m_updateRectsForGL = GetJMethod(env, clazz, "updateRectsForGL", "()V"); 151 m_javaGlue.m_viewInvalidate = GetJMethod(env, clazz, "viewInvalidate", "()V"); 152 m_javaGlue.m_viewInvalidateRect = GetJMethod(env, clazz, "viewInvalidate", "(IIII)V"); 153 m_javaGlue.m_postInvalidateDelayed = GetJMethod(env, clazz, 154 "viewInvalidateDelayed", "(JIIII)V"); 155 m_javaGlue.m_pageSwapCallback = GetJMethod(env, clazz, "pageSwapCallback", "(Z)V"); 156 env->DeleteLocalRef(clazz); 157 158 jclass rectClass = env->FindClass("android/graphics/Rect"); 159 ALOG_ASSERT(rectClass, "Could not find Rect class"); 160 m_javaGlue.m_rectLeft = env->GetFieldID(rectClass, "left", "I"); 161 m_javaGlue.m_rectTop = env->GetFieldID(rectClass, "top", "I"); 162 m_javaGlue.m_rectWidth = GetJMethod(env, rectClass, "width", "()I"); 163 m_javaGlue.m_rectHeight = GetJMethod(env, rectClass, "height", "()I"); 164 env->DeleteLocalRef(rectClass); 165 166 jclass quadFClass = env->FindClass("android/webkit/QuadF"); 167 ALOG_ASSERT(quadFClass, "Could not find QuadF class"); 168 m_javaGlue.m_quadFP1 = env->GetFieldID(quadFClass, "p1", "Landroid/graphics/PointF;"); 169 m_javaGlue.m_quadFP2 = env->GetFieldID(quadFClass, "p2", "Landroid/graphics/PointF;"); 170 m_javaGlue.m_quadFP3 = env->GetFieldID(quadFClass, "p3", "Landroid/graphics/PointF;"); 171 m_javaGlue.m_quadFP4 = env->GetFieldID(quadFClass, "p4", "Landroid/graphics/PointF;"); 172 env->DeleteLocalRef(quadFClass); 173 174 env->SetIntField(javaWebView, gWebViewField, (jint)this); 175 m_viewImpl = (WebViewCore*) viewImpl; 176 m_generation = 0; 177 m_heightCanMeasure = false; 178 m_lastDx = 0; 179 m_lastDxTime = 0; 180 m_baseLayer = 0; 181 m_glDrawFunctor = 0; 182 m_isDrawingPaused = false; 183 #if USE(ACCELERATED_COMPOSITING) 184 m_glWebViewState = 0; 185 #endif 186 } 187 188 ~WebView() 189 { 190 if (m_javaGlue.m_obj) 191 { 192 JNIEnv* env = JSC::Bindings::getJNIEnv(); 193 env->DeleteWeakGlobalRef(m_javaGlue.m_obj); 194 m_javaGlue.m_obj = 0; 195 } 196 #if USE(ACCELERATED_COMPOSITING) 197 // We must remove the m_glWebViewState prior to deleting m_baseLayer. If we 198 // do not remove it here, we risk having BaseTiles trying to paint using a 199 // deallocated base layer. 200 stopGL(); 201 #endif 202 SkSafeUnref(m_baseLayer); 203 delete m_glDrawFunctor; 204 for (int i = 0; i < DRAW_EXTRAS_SIZE; i++) 205 delete m_extras[i]; 206 } 207 208 DrawExtra* getDrawExtra(DrawExtras extras) 209 { 210 if (extras == DrawExtrasNone) 211 return 0; 212 return m_extras[extras - 1]; 213 } 214 215 void stopGL() 216 { 217 #if USE(ACCELERATED_COMPOSITING) 218 delete m_glWebViewState; 219 m_glWebViewState = 0; 220 #endif 221 } 222 223 WebViewCore* getWebViewCore() const { 224 return m_viewImpl; 225 } 226 227 void scrollRectOnScreen(const IntRect& rect) 228 { 229 if (rect.isEmpty()) 230 return; 231 int dx = 0; 232 int left = rect.x(); 233 int right = rect.maxX(); 234 if (left < m_visibleContentRect.fLeft) 235 dx = left - m_visibleContentRect.fLeft; 236 // Only scroll right if the entire width can fit on screen. 237 else if (right > m_visibleContentRect.fRight 238 && right - left < m_visibleContentRect.width()) 239 dx = right - m_visibleContentRect.fRight; 240 int dy = 0; 241 int top = rect.y(); 242 int bottom = rect.maxY(); 243 if (top < m_visibleContentRect.fTop) 244 dy = top - m_visibleContentRect.fTop; 245 // Only scroll down if the entire height can fit on screen 246 else if (bottom > m_visibleContentRect.fBottom 247 && bottom - top < m_visibleContentRect.height()) 248 dy = bottom - m_visibleContentRect.fBottom; 249 if ((dx|dy) == 0 || !scrollBy(dx, dy)) 250 return; 251 viewInvalidate(); 252 } 253 254 int drawGL(WebCore::IntRect& invScreenRect, WebCore::IntRect* invalRect, 255 WebCore::IntRect& screenRect, int titleBarHeight, 256 WebCore::IntRect& screenClip, float scale, int extras, bool shouldDraw) 257 { 258 #if USE(ACCELERATED_COMPOSITING) 259 if (!m_baseLayer) 260 return 0; 261 262 if (m_viewImpl) 263 m_viewImpl->setPrerenderingEnabled(!m_isDrawingPaused); 264 265 if (!m_glWebViewState) { 266 TilesManager::instance()->setHighEndGfx(m_isHighEndGfx); 267 m_glWebViewState = new GLWebViewState(); 268 m_glWebViewState->setBaseLayer(m_baseLayer, false, true); 269 } 270 271 DrawExtra* extra = getDrawExtra((DrawExtras) extras); 272 273 m_glWebViewState->glExtras()->setDrawExtra(extra); 274 275 // Make sure we have valid coordinates. We might not have valid coords 276 // if the zoom manager is still initializing. We will be redrawn 277 // once the correct scale is set 278 if (!m_visibleContentRect.isFinite()) 279 return 0; 280 bool treesSwapped = false; 281 bool newTreeHasAnim = false; 282 int ret = m_glWebViewState->drawGL(invScreenRect, m_visibleContentRect, invalRect, 283 screenRect, titleBarHeight, screenClip, scale, 284 &treesSwapped, &newTreeHasAnim, shouldDraw); 285 if (treesSwapped) { 286 ALOG_ASSERT(m_javaGlue.m_obj, "A java object was not associated with this native WebView!"); 287 JNIEnv* env = JSC::Bindings::getJNIEnv(); 288 AutoJObject javaObject = m_javaGlue.object(env); 289 if (javaObject.get()) { 290 env->CallVoidMethod(javaObject.get(), m_javaGlue.m_pageSwapCallback, newTreeHasAnim); 291 checkException(env); 292 } 293 } 294 return m_isDrawingPaused ? 0 : ret; 295 #endif 296 return 0; 297 } 298 299 void draw(SkCanvas* canvas, SkColor bgColor, DrawExtras extras) 300 { 301 if (!m_baseLayer) { 302 canvas->drawColor(bgColor); 303 return; 304 } 305 306 // draw the content of the base layer first 307 LayerContent* content = m_baseLayer->content(); 308 int sc = canvas->save(SkCanvas::kClip_SaveFlag); 309 if (content) { 310 canvas->clipRect(SkRect::MakeLTRB(0, 0, content->width(), content->height()), 311 SkRegion::kDifference_Op); 312 } 313 Color c = m_baseLayer->getBackgroundColor(); 314 canvas->drawColor(SkColorSetARGBInline(c.alpha(), c.red(), c.green(), c.blue())); 315 canvas->restoreToCount(sc); 316 317 // call this to be sure we've adjusted for any scrolling or animations 318 // before we actually draw 319 m_baseLayer->updatePositionsRecursive(m_visibleContentRect); 320 m_baseLayer->updatePositions(); 321 322 // We have to set the canvas' matrix on the base layer 323 // (to have fixed layers work as intended) 324 SkAutoCanvasRestore restore(canvas, true); 325 m_baseLayer->setMatrix(canvas->getTotalMatrix()); 326 canvas->resetMatrix(); 327 m_baseLayer->draw(canvas, getDrawExtra(extras)); 328 } 329 330 int getScaledMaxXScroll() 331 { 332 ALOG_ASSERT(m_javaGlue.m_obj, "A java object was not associated with this native WebView!"); 333 JNIEnv* env = JSC::Bindings::getJNIEnv(); 334 AutoJObject javaObject = m_javaGlue.object(env); 335 if (!javaObject.get()) 336 return 0; 337 int result = env->CallIntMethod(javaObject.get(), m_javaGlue.m_getScaledMaxXScroll); 338 checkException(env); 339 return result; 340 } 341 342 int getScaledMaxYScroll() 343 { 344 ALOG_ASSERT(m_javaGlue.m_obj, "A java object was not associated with this native WebView!"); 345 JNIEnv* env = JSC::Bindings::getJNIEnv(); 346 AutoJObject javaObject = m_javaGlue.object(env); 347 if (!javaObject.get()) 348 return 0; 349 int result = env->CallIntMethod(javaObject.get(), m_javaGlue.m_getScaledMaxYScroll); 350 checkException(env); 351 return result; 352 } 353 354 // Call through JNI to ask Java side to update the rectangles for GL functor. 355 // This is called at every draw when it is not in process mode, so we should 356 // keep this route as efficient as possible. Currently, its average cost on Xoom 357 // is about 0.1ms - 0.2ms. 358 // Alternatively, this can be achieved by adding more listener on Java side, but 359 // that will be more likely causing jank when triggering GC. 360 void updateRectsForGL() 361 { 362 JNIEnv* env = JSC::Bindings::getJNIEnv(); 363 AutoJObject javaObject = m_javaGlue.object(env); 364 if (!javaObject.get()) 365 return; 366 env->CallVoidMethod(javaObject.get(), m_javaGlue.m_updateRectsForGL); 367 checkException(env); 368 } 369 370 #if USE(ACCELERATED_COMPOSITING) 371 static const ScrollableLayerAndroid* findScrollableLayer( 372 const LayerAndroid* parent, int x, int y, SkIRect* foundBounds) { 373 IntRect bounds = enclosingIntRect(parent->fullContentAreaMapped()); 374 375 // Check the parent bounds first; this will clip to within a masking layer's 376 // bounds. 377 if (parent->masksToBounds() && !bounds.contains(x, y)) 378 return 0; 379 380 int count = parent->countChildren(); 381 while (count--) { 382 const LayerAndroid* child = parent->getChild(count); 383 const ScrollableLayerAndroid* result = findScrollableLayer(child, x, y, foundBounds); 384 if (result) { 385 if (parent->masksToBounds()) { 386 if (bounds.width() < foundBounds->width()) 387 foundBounds->fRight = foundBounds->fLeft + bounds.width(); 388 if (bounds.height() < foundBounds->height()) 389 foundBounds->fBottom = foundBounds->fTop + bounds.height(); 390 } 391 return result; 392 } 393 } 394 if (parent->contentIsScrollable()) { 395 foundBounds->set(bounds.x(), bounds.y(), bounds.width(), bounds.height()); 396 return static_cast<const ScrollableLayerAndroid*>(parent); 397 } 398 return 0; 399 } 400 #endif 401 402 int scrollableLayer(int x, int y, SkIRect* layerRect, SkIRect* bounds) 403 { 404 #if USE(ACCELERATED_COMPOSITING) 405 if (!m_baseLayer) 406 return 0; 407 const ScrollableLayerAndroid* result = findScrollableLayer(m_baseLayer, x, y, bounds); 408 if (result) { 409 result->getScrollRect(layerRect); 410 return result->uniqueId(); 411 } 412 #endif 413 return 0; 414 } 415 416 void scrollLayer(int layerId, int x, int y) 417 { 418 if (m_glWebViewState) 419 m_glWebViewState->scrollLayer(layerId, x, y); 420 } 421 422 void setHeightCanMeasure(bool measure) 423 { 424 m_heightCanMeasure = measure; 425 } 426 427 String getSelection() 428 { 429 SelectText* select = static_cast<SelectText*>( 430 getDrawExtra(WebView::DrawExtrasSelection)); 431 if (select) 432 return select->getText(); 433 return String(); 434 } 435 436 bool scrollBy(int dx, int dy) 437 { 438 ALOG_ASSERT(m_javaGlue.m_obj, "A java object was not associated with this native WebView!"); 439 440 JNIEnv* env = JSC::Bindings::getJNIEnv(); 441 AutoJObject javaObject = m_javaGlue.object(env); 442 if (!javaObject.get()) 443 return false; 444 bool result = env->CallBooleanMethod(javaObject.get(), m_javaGlue.m_scrollBy, dx, dy, true); 445 checkException(env); 446 return result; 447 } 448 449 void setIsScrolling(bool isScrolling) 450 { 451 #if USE(ACCELERATED_COMPOSITING) 452 if (m_glWebViewState) 453 m_glWebViewState->setIsScrolling(isScrolling); 454 #endif 455 } 456 457 void viewInvalidate() 458 { 459 JNIEnv* env = JSC::Bindings::getJNIEnv(); 460 AutoJObject javaObject = m_javaGlue.object(env); 461 if (!javaObject.get()) 462 return; 463 env->CallVoidMethod(javaObject.get(), m_javaGlue.m_viewInvalidate); 464 checkException(env); 465 } 466 467 void viewInvalidateRect(int l, int t, int r, int b) 468 { 469 JNIEnv* env = JSC::Bindings::getJNIEnv(); 470 AutoJObject javaObject = m_javaGlue.object(env); 471 if (!javaObject.get()) 472 return; 473 env->CallVoidMethod(javaObject.get(), m_javaGlue.m_viewInvalidateRect, l, r, t, b); 474 checkException(env); 475 } 476 477 void postInvalidateDelayed(int64_t delay, const WebCore::IntRect& bounds) 478 { 479 JNIEnv* env = JSC::Bindings::getJNIEnv(); 480 AutoJObject javaObject = m_javaGlue.object(env); 481 if (!javaObject.get()) 482 return; 483 env->CallVoidMethod(javaObject.get(), m_javaGlue.m_postInvalidateDelayed, 484 delay, bounds.x(), bounds.y(), bounds.maxX(), bounds.maxY()); 485 checkException(env); 486 } 487 488 #if ENABLE(ANDROID_OVERFLOW_SCROLL) 489 static void copyScrollPosition(const LayerAndroid* fromRoot, 490 LayerAndroid* toRoot, int layerId) 491 { 492 if (!fromRoot || !toRoot) 493 return; 494 const LayerAndroid* from = fromRoot->findById(layerId); 495 LayerAndroid* to = toRoot->findById(layerId); 496 if (!from || !to || !from->contentIsScrollable() || !to->contentIsScrollable()) 497 return; 498 // TODO: Support this for iframes. 499 if (to->isIFrameContent() || from->isIFrameContent()) 500 return; 501 to->setScrollOffset(from->getScrollOffset()); 502 } 503 #endif 504 505 BaseLayerAndroid* getBaseLayer() const { return m_baseLayer; } 506 507 bool setBaseLayer(BaseLayerAndroid* newBaseLayer, bool showVisualIndicator, 508 bool isPictureAfterFirstLayout, int scrollingLayer) 509 { 510 bool queueFull = false; 511 #if USE(ACCELERATED_COMPOSITING) 512 if (m_glWebViewState) 513 queueFull = m_glWebViewState->setBaseLayer(newBaseLayer, showVisualIndicator, 514 isPictureAfterFirstLayout); 515 #endif 516 517 #if ENABLE(ANDROID_OVERFLOW_SCROLL) 518 copyScrollPosition(m_baseLayer, newBaseLayer, scrollingLayer); 519 #endif 520 SkSafeUnref(m_baseLayer); 521 m_baseLayer = newBaseLayer; 522 523 return queueFull; 524 } 525 526 void copyBaseContentToPicture(SkPicture* picture) 527 { 528 if (!m_baseLayer || !m_baseLayer->content()) 529 return; 530 LayerContent* content = m_baseLayer->content(); 531 SkCanvas* canvas = picture->beginRecording(content->width(), content->height(), 532 SkPicture::kUsePathBoundsForClip_RecordingFlag); 533 534 // clear the BaseLayerAndroid's previous matrix (set at each draw) 535 SkMatrix baseMatrix; 536 baseMatrix.reset(); 537 m_baseLayer->setMatrix(baseMatrix); 538 539 m_baseLayer->draw(canvas, 0); 540 541 picture->endRecording(); 542 } 543 544 bool hasContent() { 545 if (!m_baseLayer || !m_baseLayer->content()) 546 return false; 547 return !m_baseLayer->content()->isEmpty(); 548 } 549 550 void setFunctor(Functor* functor) { 551 delete m_glDrawFunctor; 552 m_glDrawFunctor = functor; 553 } 554 555 Functor* getFunctor() { 556 return m_glDrawFunctor; 557 } 558 559 void setVisibleContentRect(SkRect& visibleContentRect) { 560 m_visibleContentRect = visibleContentRect; 561 } 562 563 void setDrawExtra(DrawExtra *extra, DrawExtras type) 564 { 565 if (type == DrawExtrasNone) 566 return; 567 DrawExtra* old = m_extras[type - 1]; 568 m_extras[type - 1] = extra; 569 if (old != extra) { 570 delete old; 571 } 572 } 573 574 void setTextSelection(SelectText *selection) { 575 setDrawExtra(selection, DrawExtrasSelection); 576 } 577 578 const TransformationMatrix* getLayerTransform(int layerId) { 579 if (layerId != -1 && m_baseLayer) { 580 LayerAndroid* layer = m_baseLayer->findById(layerId); 581 // We need to make sure the drawTransform is up to date as this is 582 // called before a draw() or drawGL() 583 if (layer) { 584 m_baseLayer->updatePositionsRecursive(m_visibleContentRect); 585 return layer->drawTransform(); 586 } 587 } 588 return 0; 589 } 590 591 int getHandleLayerId(SelectText::HandleId handleId, SkIPoint& cursorPoint, 592 FloatQuad& textBounds) { 593 SelectText* selectText = static_cast<SelectText*>(getDrawExtra(DrawExtrasSelection)); 594 if (!selectText || !m_baseLayer) 595 return -1; 596 int layerId = selectText->caretLayerId(handleId); 597 IntRect cursorRect = selectText->caretRect(handleId); 598 IntRect textRect = selectText->textRect(handleId); 599 // Rects exclude the last pixel on right/bottom. We want only included pixels. 600 cursorPoint.set(cursorRect.x(), cursorRect.maxY() - 1); 601 textRect.setHeight(std::max(1, textRect.height() - 1)); 602 textRect.setWidth(std::max(1, textRect.width() - 1)); 603 textBounds = FloatQuad(textRect); 604 605 const TransformationMatrix* transform = getLayerTransform(layerId); 606 if (transform) { 607 // We're overloading the concept of Rect to be just the two 608 // points (bottom-left and top-right. 609 cursorPoint = transform->mapPoint(cursorPoint); 610 textBounds = transform->mapQuad(textBounds); 611 } 612 return layerId; 613 } 614 615 void mapLayerRect(int layerId, SkIRect& rect) { 616 const TransformationMatrix* transform = getLayerTransform(layerId); 617 if (transform) 618 rect = transform->mapRect(rect); 619 } 620 621 void floatQuadToQuadF(JNIEnv* env, const FloatQuad& nativeTextQuad, 622 jobject textQuad) 623 { 624 jobject p1 = env->GetObjectField(textQuad, m_javaGlue.m_quadFP1); 625 jobject p2 = env->GetObjectField(textQuad, m_javaGlue.m_quadFP2); 626 jobject p3 = env->GetObjectField(textQuad, m_javaGlue.m_quadFP3); 627 jobject p4 = env->GetObjectField(textQuad, m_javaGlue.m_quadFP4); 628 GraphicsJNI::point_to_jpointf(nativeTextQuad.p1(), env, p1); 629 GraphicsJNI::point_to_jpointf(nativeTextQuad.p2(), env, p2); 630 GraphicsJNI::point_to_jpointf(nativeTextQuad.p3(), env, p3); 631 GraphicsJNI::point_to_jpointf(nativeTextQuad.p4(), env, p4); 632 env->DeleteLocalRef(p1); 633 env->DeleteLocalRef(p2); 634 env->DeleteLocalRef(p3); 635 env->DeleteLocalRef(p4); 636 } 637 638 // This is called when WebView switches rendering modes in a more permanent fashion 639 // such as when the layer type is set or the view is attached/detached from the window 640 int setHwAccelerated(bool hwAccelerated) { 641 if (!m_glWebViewState) 642 return 0; 643 LayerAndroid* root = m_baseLayer; 644 if (root) 645 return root->setHwAccelerated(hwAccelerated); 646 return 0; 647 } 648 649 void setDrawingPaused(bool isPaused) 650 { 651 m_isDrawingPaused = isPaused; 652 if (m_viewImpl) 653 m_viewImpl->setPrerenderingEnabled(!isPaused); 654 } 655 656 // Finds the rectangles within world to the left, right, top, and bottom 657 // of rect and adds them to rects. If no intersection exists, false is returned. 658 static bool findMaskedRects(const FloatRect& world, 659 const FloatRect& rect, Vector<FloatRect>& rects) { 660 if (!world.intersects(rect)) 661 return false; // nothing to subtract 662 663 // left rectangle 664 if (rect.x() > world.x()) 665 rects.append(FloatRect(world.x(), world.y(), 666 rect.x() - world.x(), world.height())); 667 // top rectangle 668 if (rect.y() > world.y()) 669 rects.append(FloatRect(world.x(), world.y(), 670 world.width(), rect.y() - world.y())); 671 // right rectangle 672 if (rect.maxX() < world.maxX()) 673 rects.append(FloatRect(rect.maxX(), world.y(), 674 world.maxX() - rect.maxX(), world.height())); 675 // bottom rectangle 676 if (rect.maxY() < world.maxY()) 677 rects.append(FloatRect(world.x(), rect.maxY(), 678 world.width(), world.maxY() - rect.maxY())); 679 return true; 680 } 681 682 // Returns false if layerId is a fixed position layer, otherwise 683 // all fixed position layer rectangles are subtracted from those within 684 // rects. Rects will be modified to contain rectangles that don't include 685 // the fixed position layer rectangles. 686 static bool findMaskedRectsForLayer(LayerAndroid* layer, 687 Vector<FloatRect>& rects, int layerId) 688 { 689 if (layer->isPositionFixed()) { 690 if (layerId == layer->uniqueId()) 691 return false; 692 FloatRect layerRect = layer->fullContentAreaMapped(); 693 for (int i = rects.size() - 1; i >= 0; i--) 694 if (findMaskedRects(rects[i], layerRect, rects)) 695 rects.remove(i); 696 } 697 698 int childIndex = 0; 699 while (LayerAndroid* child = layer->getChild(childIndex++)) 700 if (!findMaskedRectsForLayer(child, rects, layerId)) 701 return false; 702 703 return true; 704 } 705 706 // Finds the largest rectangle not masked by any fixed layer. 707 void findMaxVisibleRect(int movingLayerId, SkIRect& visibleContentRect) 708 { 709 if (!m_baseLayer) 710 return; 711 712 FloatRect visibleContentFloatRect(visibleContentRect); 713 m_baseLayer->updatePositionsRecursive(visibleContentFloatRect); 714 Vector<FloatRect> rects; 715 rects.append(visibleContentFloatRect); 716 if (findMaskedRectsForLayer(m_baseLayer, rects, movingLayerId)) { 717 float maxSize = 0.0; 718 const FloatRect* largest = 0; 719 for (unsigned int i = 0; i < rects.size(); i++) { 720 const FloatRect& rect = rects[i]; 721 float size = rect.width() * rect.height(); 722 if (size > maxSize) { 723 maxSize = size; 724 largest = ▭ 725 } 726 } 727 if (largest) { 728 SkRect largeRect = *largest; 729 largeRect.round(&visibleContentRect); 730 } 731 } 732 } 733 734 bool isHandleLeft(SelectText::HandleId handleId) 735 { 736 SelectText* selectText = static_cast<SelectText*>(getDrawExtra(DrawExtrasSelection)); 737 if (!selectText) 738 return (handleId == SelectText::BaseHandle); 739 740 return (selectText->getHandleType(handleId) == SelectText::LeftHandle); 741 } 742 743 bool isPointVisible(int layerId, int contentX, int contentY) 744 { 745 bool isVisible = true; 746 const TransformationMatrix* transform = getLayerTransform(layerId); 747 if (transform) { 748 // layer is guaranteed to be non-NULL because of getLayerTransform 749 LayerAndroid* layer = m_baseLayer->findById(layerId); 750 IntRect rect = layer->visibleContentArea(); 751 rect = transform->mapRect(rect); 752 isVisible = rect.contains(contentX, contentY); 753 } 754 return isVisible; 755 } 756 757 private: // local state for WebView 758 bool m_isDrawingPaused; 759 // private to getFrameCache(); other functions operate in a different thread 760 WebViewCore* m_viewImpl; 761 int m_generation; // associate unique ID with sent kit focus to match with ui 762 // Corresponds to the same-named boolean on the java side. 763 bool m_heightCanMeasure; 764 int m_lastDx; 765 SkMSec m_lastDxTime; 766 DrawExtra* m_extras[DRAW_EXTRAS_SIZE]; 767 BaseLayerAndroid* m_baseLayer; 768 Functor* m_glDrawFunctor; 769 #if USE(ACCELERATED_COMPOSITING) 770 GLWebViewState* m_glWebViewState; 771 #endif 772 SkRect m_visibleContentRect; 773 bool m_isHighEndGfx; 774 }; // end of WebView class 775 776 777 /** 778 * This class holds a function pointer and parameters for calling drawGL into a specific 779 * viewport. The pointer to the Functor will be put on a framework display list to be called 780 * when the display list is replayed. 781 */ 782 class GLDrawFunctor : Functor { 783 public: 784 GLDrawFunctor(WebView* _wvInstance, 785 int (WebView::*_funcPtr)(WebCore::IntRect&, WebCore::IntRect*, 786 WebCore::IntRect&, int, WebCore::IntRect&, jfloat, jint, bool), 787 WebCore::IntRect _invScreenRect, float _scale, int _extras) { 788 wvInstance = _wvInstance; 789 funcPtr = _funcPtr; 790 invScreenRect = _invScreenRect; 791 scale = _scale; 792 extras = _extras; 793 }; 794 795 status_t operator()(int messageId, void* data) { 796 TRACE_METHOD(); 797 bool shouldDraw = (messageId == uirenderer::DrawGlInfo::kModeDraw); 798 if (shouldDraw) 799 wvInstance->updateRectsForGL(); 800 801 if (invScreenRect.isEmpty()) { 802 // NOOP operation if viewport is empty 803 return 0; 804 } 805 806 WebCore::IntRect inval; 807 int titlebarHeight = screenRect.height() - invScreenRect.height(); 808 809 uirenderer::DrawGlInfo* info = reinterpret_cast<uirenderer::DrawGlInfo*>(data); 810 WebCore::IntRect screenClip(info->clipLeft, info->clipTop, 811 info->clipRight - info->clipLeft, 812 info->clipBottom - info->clipTop); 813 814 WebCore::IntRect localInvScreenRect = invScreenRect; 815 if (info->isLayer) { 816 // When webview is on a layer, we need to use the viewport relative 817 // to the FBO, rather than the screen(which will use invScreenRect). 818 localInvScreenRect.setX(screenClip.x()); 819 localInvScreenRect.setY(info->height - screenClip.y() - screenClip.height()); 820 } 821 // Send the necessary info to the shader. 822 TilesManager::instance()->shader()->setGLDrawInfo(info); 823 824 int returnFlags = (*wvInstance.*funcPtr)(localInvScreenRect, &inval, screenRect, 825 titlebarHeight, screenClip, scale, extras, shouldDraw); 826 if ((returnFlags & uirenderer::DrawGlInfo::kStatusDraw) != 0) { 827 IntRect finalInval; 828 if (inval.isEmpty()) 829 finalInval = screenRect; 830 else { 831 finalInval.setX(screenRect.x() + inval.x()); 832 finalInval.setY(screenRect.y() + titlebarHeight + inval.y()); 833 finalInval.setWidth(inval.width()); 834 finalInval.setHeight(inval.height()); 835 } 836 info->dirtyLeft = finalInval.x(); 837 info->dirtyTop = finalInval.y(); 838 info->dirtyRight = finalInval.maxX(); 839 info->dirtyBottom = finalInval.maxY(); 840 } 841 // return 1 if invalidation needed, 2 to request non-drawing functor callback, 0 otherwise 842 ALOGV("returnFlags are %d, shouldDraw %d", returnFlags, shouldDraw); 843 return returnFlags; 844 } 845 void updateScreenRect(WebCore::IntRect& _screenRect) { 846 screenRect = _screenRect; 847 } 848 void updateInvScreenRect(WebCore::IntRect& _invScreenRect) { 849 invScreenRect = _invScreenRect; 850 } 851 void updateScale(float _scale) { 852 scale = _scale; 853 } 854 void updateExtras(jint _extras) { 855 extras = _extras; 856 } 857 private: 858 WebView* wvInstance; 859 int (WebView::*funcPtr)(WebCore::IntRect&, WebCore::IntRect*, 860 WebCore::IntRect&, int, WebCore::IntRect&, float, int, bool); 861 WebCore::IntRect invScreenRect; 862 WebCore::IntRect screenRect; 863 jfloat scale; 864 jint extras; 865 }; 866 867 /* 868 * Native JNI methods 869 */ 870 871 static void nativeCreate(JNIEnv *env, jobject obj, int viewImpl, 872 jstring drawableDir, jboolean isHighEndGfx) 873 { 874 WTF::String dir = jstringToWtfString(env, drawableDir); 875 new WebView(env, obj, viewImpl, dir, isHighEndGfx); 876 // NEED THIS OR SOMETHING LIKE IT! 877 //Release(obj); 878 } 879 880 static WebCore::IntRect jrect_to_webrect(JNIEnv* env, jobject obj) 881 { 882 if (obj) { 883 int L, T, R, B; 884 GraphicsJNI::get_jrect(env, obj, &L, &T, &R, &B); 885 return WebCore::IntRect(L, T, R - L, B - T); 886 } else 887 return WebCore::IntRect(); 888 } 889 890 static SkRect jrectf_to_rect(JNIEnv* env, jobject obj) 891 { 892 SkRect rect = SkRect::MakeEmpty(); 893 if (obj) 894 GraphicsJNI::jrectf_to_rect(env, obj, &rect); 895 return rect; 896 } 897 898 static void nativeDraw(JNIEnv *env, jobject obj, jobject canv, 899 jobject visible, jint color, 900 jint extras) { 901 SkCanvas* canvas = GraphicsJNI::getNativeCanvas(env, canv); 902 WebView* webView = GET_NATIVE_VIEW(env, obj); 903 SkRect visibleContentRect = jrectf_to_rect(env, visible); 904 webView->setVisibleContentRect(visibleContentRect); 905 webView->draw(canvas, color, static_cast<WebView::DrawExtras>(extras)); 906 } 907 908 static jint nativeCreateDrawGLFunction(JNIEnv *env, jobject obj, jint nativeView, 909 jobject jinvscreenrect, jobject jscreenrect, 910 jobject jvisiblecontentrect, 911 jfloat scale, jint extras) { 912 WebCore::IntRect invScreenRect = jrect_to_webrect(env, jinvscreenrect); 913 WebView *wvInstance = reinterpret_cast<WebView*>(nativeView); 914 SkRect visibleContentRect = jrectf_to_rect(env, jvisiblecontentrect); 915 wvInstance->setVisibleContentRect(visibleContentRect); 916 917 GLDrawFunctor* functor = (GLDrawFunctor*) wvInstance->getFunctor(); 918 if (!functor) { 919 functor = new GLDrawFunctor(wvInstance, &android::WebView::drawGL, 920 invScreenRect, scale, extras); 921 wvInstance->setFunctor((Functor*) functor); 922 } else { 923 functor->updateInvScreenRect(invScreenRect); 924 functor->updateScale(scale); 925 functor->updateExtras(extras); 926 } 927 928 WebCore::IntRect rect = jrect_to_webrect(env, jscreenrect); 929 functor->updateScreenRect(rect); 930 931 return (jint)functor; 932 } 933 934 static jint nativeGetDrawGLFunction(JNIEnv *env, jobject obj, jint nativeView) { 935 WebView *wvInstance = reinterpret_cast<WebView*>(nativeView); 936 if (!wvInstance) 937 return 0; 938 939 return (jint) wvInstance->getFunctor(); 940 } 941 942 static void nativeUpdateDrawGLFunction(JNIEnv *env, jobject obj, jint nativeView, 943 jobject jinvscreenrect, jobject jscreenrect, 944 jobject jvisiblecontentrect, jfloat scale) { 945 WebView *wvInstance = reinterpret_cast<WebView*>(nativeView); 946 if (wvInstance) { 947 GLDrawFunctor* functor = (GLDrawFunctor*) wvInstance->getFunctor(); 948 if (functor) { 949 WebCore::IntRect invScreenRect = jrect_to_webrect(env, jinvscreenrect); 950 functor->updateInvScreenRect(invScreenRect); 951 952 SkRect visibleContentRect = jrectf_to_rect(env, jvisiblecontentrect); 953 wvInstance->setVisibleContentRect(visibleContentRect); 954 955 WebCore::IntRect screenRect = jrect_to_webrect(env, jscreenrect); 956 functor->updateScreenRect(screenRect); 957 958 functor->updateScale(scale); 959 } 960 } 961 } 962 963 static bool nativeEvaluateLayersAnimations(JNIEnv *env, jobject obj, jint nativeView) 964 { 965 // only call in software rendering, initialize and evaluate animations 966 #if USE(ACCELERATED_COMPOSITING) 967 BaseLayerAndroid* baseLayer = reinterpret_cast<WebView*>(nativeView)->getBaseLayer(); 968 if (baseLayer) { 969 baseLayer->initAnimations(); 970 return baseLayer->evaluateAnimations(); 971 } 972 #endif 973 return false; 974 } 975 976 static bool nativeSetBaseLayer(JNIEnv *env, jobject obj, jint nativeView, jint layer, 977 jboolean showVisualIndicator, 978 jboolean isPictureAfterFirstLayout, 979 jint scrollingLayer) 980 { 981 BaseLayerAndroid* layerImpl = reinterpret_cast<BaseLayerAndroid*>(layer); 982 return reinterpret_cast<WebView*>(nativeView)->setBaseLayer(layerImpl, showVisualIndicator, 983 isPictureAfterFirstLayout, 984 scrollingLayer); 985 } 986 987 static BaseLayerAndroid* nativeGetBaseLayer(JNIEnv *env, jobject obj, jint nativeView) 988 { 989 return reinterpret_cast<WebView*>(nativeView)->getBaseLayer(); 990 } 991 992 static void nativeCopyBaseContentToPicture(JNIEnv *env, jobject obj, jobject pict) 993 { 994 SkPicture* picture = GraphicsJNI::getNativePicture(env, pict); 995 GET_NATIVE_VIEW(env, obj)->copyBaseContentToPicture(picture); 996 } 997 998 static jboolean nativeDumpLayerContentToPicture(JNIEnv *env, jobject obj, jint instance, 999 jstring jclassName, jint layerId, jobject pict) 1000 { 1001 bool success = false; 1002 SkPicture* picture = GraphicsJNI::getNativePicture(env, pict); 1003 std::string classname = jstringToStdString(env, jclassName); 1004 BaseLayerAndroid* baseLayer = reinterpret_cast<WebView*>(instance)->getBaseLayer(); 1005 LayerAndroid* layer = baseLayer->findById(layerId); 1006 SkSafeRef(layer); 1007 if (layer && layer->subclassName() == classname) { 1008 LayerContent* content = layer->content(); 1009 if (content) { 1010 SkCanvas* canvas = picture->beginRecording(content->width(), content->height()); 1011 content->draw(canvas); 1012 picture->endRecording(); 1013 success = true; 1014 } 1015 } 1016 SkSafeUnref(layer); 1017 return success; 1018 } 1019 1020 static bool nativeHasContent(JNIEnv *env, jobject obj) 1021 { 1022 return GET_NATIVE_VIEW(env, obj)->hasContent(); 1023 } 1024 1025 static void nativeSetHeightCanMeasure(JNIEnv *env, jobject obj, bool measure) 1026 { 1027 WebView* view = GET_NATIVE_VIEW(env, obj); 1028 ALOG_ASSERT(view, "view not set in nativeSetHeightCanMeasure"); 1029 view->setHeightCanMeasure(measure); 1030 } 1031 1032 static void nativeDestroy(JNIEnv *env, jobject obj, jint ptr) 1033 { 1034 WebView* view = reinterpret_cast<WebView*>(ptr); 1035 ALOGD("nativeDestroy view: %p", view); 1036 ALOG_ASSERT(view, "view not set in nativeDestroy"); 1037 delete view; 1038 } 1039 1040 static void nativeStopGL(JNIEnv *env, jobject obj, jint ptr) 1041 { 1042 if (ptr) 1043 reinterpret_cast<WebView*>(ptr)->stopGL(); 1044 } 1045 1046 static jobject nativeGetSelection(JNIEnv *env, jobject obj) 1047 { 1048 WebView* view = GET_NATIVE_VIEW(env, obj); 1049 ALOG_ASSERT(view, "view not set in %s", __FUNCTION__); 1050 String selection = view->getSelection(); 1051 return wtfStringToJstring(env, selection); 1052 } 1053 1054 static void nativeDiscardAllTextures(JNIEnv *env, jobject obj) 1055 { 1056 //discard all textures for debugging/test purposes, but not gl backing memory 1057 bool allTextures = true, deleteGLTextures = false; 1058 TilesManager::instance()->discardTextures(allTextures, deleteGLTextures); 1059 } 1060 1061 static void nativeTileProfilingStart(JNIEnv *env, jobject obj) 1062 { 1063 TilesManager::instance()->getProfiler()->start(); 1064 } 1065 1066 static float nativeTileProfilingStop(JNIEnv *env, jobject obj) 1067 { 1068 return TilesManager::instance()->getProfiler()->stop(); 1069 } 1070 1071 static void nativeTileProfilingClear(JNIEnv *env, jobject obj) 1072 { 1073 TilesManager::instance()->getProfiler()->clear(); 1074 } 1075 1076 static int nativeTileProfilingNumFrames(JNIEnv *env, jobject obj) 1077 { 1078 return TilesManager::instance()->getProfiler()->numFrames(); 1079 } 1080 1081 static int nativeTileProfilingNumTilesInFrame(JNIEnv *env, jobject obj, int frame) 1082 { 1083 return TilesManager::instance()->getProfiler()->numTilesInFrame(frame); 1084 } 1085 1086 static int nativeTileProfilingGetInt(JNIEnv *env, jobject obj, int frame, int tile, jstring jkey) 1087 { 1088 WTF::String key = jstringToWtfString(env, jkey); 1089 TileProfileRecord* record = TilesManager::instance()->getProfiler()->getTile(frame, tile); 1090 1091 if (key == "left") 1092 return record->left; 1093 if (key == "top") 1094 return record->top; 1095 if (key == "right") 1096 return record->right; 1097 if (key == "bottom") 1098 return record->bottom; 1099 if (key == "level") 1100 return record->level; 1101 if (key == "isReady") 1102 return record->isReady ? 1 : 0; 1103 return -1; 1104 } 1105 1106 static float nativeTileProfilingGetFloat(JNIEnv *env, jobject obj, int frame, int tile, jstring jkey) 1107 { 1108 TileProfileRecord* record = TilesManager::instance()->getProfiler()->getTile(frame, tile); 1109 return record->scale; 1110 } 1111 1112 #ifdef ANDROID_DUMP_DISPLAY_TREE 1113 static void dumpToFile(const char text[], void* file) { 1114 fwrite(text, 1, strlen(text), reinterpret_cast<FILE*>(file)); 1115 fwrite("\n", 1, 1, reinterpret_cast<FILE*>(file)); 1116 } 1117 #endif 1118 1119 // Return true to view invalidate WebView 1120 static bool nativeSetProperty(JNIEnv *env, jobject obj, jstring jkey, jstring jvalue) 1121 { 1122 WTF::String key = jstringToWtfString(env, jkey); 1123 WTF::String value = jstringToWtfString(env, jvalue); 1124 if (key == "inverted") { 1125 bool shouldInvert = (value == "true"); 1126 TilesManager::instance()->setInvertedScreen(shouldInvert); 1127 return true; 1128 } 1129 else if (key == "inverted_contrast") { 1130 float contrast = value.toFloat(); 1131 TilesManager::instance()->setInvertedScreenContrast(contrast); 1132 return true; 1133 } 1134 else if (key == "enable_cpu_upload_path") { 1135 TilesManager::instance()->transferQueue()->setTextureUploadType( 1136 value == "true" ? CpuUpload : GpuUpload); 1137 } 1138 else if (key == "use_minimal_memory") { 1139 TilesManager::instance()->setUseMinimalMemory(value == "true"); 1140 } 1141 else if (key == "use_double_buffering") { 1142 TilesManager::instance()->setUseDoubleBuffering(value == "true"); 1143 } 1144 else if (key == "tree_updates") { 1145 TilesManager::instance()->clearContentUpdates(); 1146 } 1147 return false; 1148 } 1149 1150 static jstring nativeGetProperty(JNIEnv *env, jobject obj, jstring jkey) 1151 { 1152 WTF::String key = jstringToWtfString(env, jkey); 1153 if (key == "tree_updates") { 1154 int updates = TilesManager::instance()->getContentUpdates(); 1155 WTF::String wtfUpdates = WTF::String::number(updates); 1156 return wtfStringToJstring(env, wtfUpdates); 1157 } 1158 return 0; 1159 } 1160 1161 static void nativeOnTrimMemory(JNIEnv *env, jobject obj, jint level) 1162 { 1163 if (TilesManager::hardwareAccelerationEnabled()) { 1164 // When we got TRIM_MEMORY_MODERATE or TRIM_MEMORY_COMPLETE, we should 1165 // make sure the transfer queue is empty and then abandon the Surface 1166 // Texture to avoid ANR b/c framework may destroy the EGL context. 1167 // Refer to WindowManagerImpl.java for conditions we followed. 1168 TilesManager* tilesManager = TilesManager::instance(); 1169 if ((level >= TRIM_MEMORY_MODERATE 1170 && !tilesManager->highEndGfx()) 1171 || level >= TRIM_MEMORY_COMPLETE) { 1172 ALOGD("OnTrimMemory with EGL Context %p", eglGetCurrentContext()); 1173 tilesManager->cleanupGLResources(); 1174 } 1175 1176 bool freeAllTextures = (level > TRIM_MEMORY_UI_HIDDEN), glTextures = true; 1177 tilesManager->discardTextures(freeAllTextures, glTextures); 1178 } 1179 } 1180 1181 static void nativeDumpDisplayTree(JNIEnv* env, jobject jwebview, jstring jurl) 1182 { 1183 #if defined(ANDROID_DUMP_DISPLAY_TREE) && defined(SK_DEVELOPER) 1184 WebView* view = GET_NATIVE_VIEW(env, jwebview); 1185 ALOG_ASSERT(view, "view not set in %s", __FUNCTION__); 1186 1187 if (view && view->getWebViewCore()) { 1188 FILE* file = fopen(DISPLAY_TREE_LOG_FILE, "w"); 1189 if (file) { 1190 SkFormatDumper dumper(dumpToFile, file); 1191 // dump the URL 1192 if (jurl) { 1193 const char* str = env->GetStringUTFChars(jurl, 0); 1194 SkDebugf("Dumping %s to %s\n", str, DISPLAY_TREE_LOG_FILE); 1195 dumpToFile(str, file); 1196 env->ReleaseStringUTFChars(jurl, str); 1197 } 1198 // now dump the display tree 1199 SkDumpCanvas canvas(&dumper); 1200 // this will playback the picture into the canvas, which will 1201 // spew its contents to the dumper 1202 view->draw(&canvas, 0, WebView::DrawExtrasNone); 1203 // we're done with the file now 1204 fwrite("\n", 1, 1, file); 1205 fclose(file); 1206 } 1207 #if USE(ACCELERATED_COMPOSITING) 1208 const LayerAndroid* baseLayer = view->getBaseLayer(); 1209 if (baseLayer) { 1210 FILE* file = fopen(LAYERS_TREE_LOG_FILE,"w"); 1211 if (file) { 1212 WebCore::FileLayerDumper dumper(file); 1213 baseLayer->dumpLayers(&dumper); 1214 fclose(file); 1215 } 1216 } 1217 #endif 1218 } 1219 #endif 1220 } 1221 1222 static int nativeScrollableLayer(JNIEnv* env, jobject jwebview, jint nativeView, 1223 jint x, jint y, jobject rect, jobject bounds) 1224 { 1225 WebView* webview = reinterpret_cast<WebView*>(nativeView); 1226 ALOG_ASSERT(webview, "webview not set in %s", __FUNCTION__); 1227 SkIRect nativeRect, nativeBounds; 1228 int id = webview->scrollableLayer(x, y, &nativeRect, &nativeBounds); 1229 if (rect) 1230 GraphicsJNI::irect_to_jrect(nativeRect, env, rect); 1231 if (bounds) 1232 GraphicsJNI::irect_to_jrect(nativeBounds, env, bounds); 1233 return id; 1234 } 1235 1236 static bool nativeScrollLayer(JNIEnv* env, jobject obj, 1237 jint nativeView, jint layerId, jint x, jint y) 1238 { 1239 #if ENABLE(ANDROID_OVERFLOW_SCROLL) 1240 WebView* webview = reinterpret_cast<WebView*>(nativeView); 1241 webview->scrollLayer(layerId, x, y); 1242 1243 //TODO: the below only needed for the SW rendering path 1244 LayerAndroid* baseLayer = webview->getBaseLayer(); 1245 if (!baseLayer) 1246 return false; 1247 LayerAndroid* layer = baseLayer->findById(layerId); 1248 if (!layer || !layer->contentIsScrollable()) 1249 return false; 1250 return static_cast<ScrollableLayerAndroid*>(layer)->scrollTo(x, y); 1251 #endif 1252 return false; 1253 } 1254 1255 static void nativeSetIsScrolling(JNIEnv* env, jobject jwebview, jboolean isScrolling) 1256 { 1257 // TODO: Pass in the native pointer instead 1258 WebView* view = GET_NATIVE_VIEW(env, jwebview); 1259 if (view) 1260 view->setIsScrolling(isScrolling); 1261 } 1262 1263 static void nativeUseHardwareAccelSkia(JNIEnv*, jobject, jboolean enabled) 1264 { 1265 BaseRenderer::setCurrentRendererType(enabled ? BaseRenderer::Ganesh : BaseRenderer::Raster); 1266 } 1267 1268 static int nativeGetBackgroundColor(JNIEnv* env, jobject obj, jint nativeView) 1269 { 1270 WebView* view = reinterpret_cast<WebView*>(nativeView); 1271 BaseLayerAndroid* baseLayer = view->getBaseLayer(); 1272 if (baseLayer) { 1273 WebCore::Color color = baseLayer->getBackgroundColor(); 1274 if (color.isValid()) 1275 return SkColorSetARGB(color.alpha(), color.red(), 1276 color.green(), color.blue()); 1277 } 1278 return SK_ColorWHITE; 1279 } 1280 1281 static void nativeSetPauseDrawing(JNIEnv *env, jobject obj, jint nativeView, 1282 jboolean pause) 1283 { 1284 reinterpret_cast<WebView*>(nativeView)->setDrawingPaused(pause); 1285 } 1286 1287 static void nativeSetTextSelection(JNIEnv *env, jobject obj, jint nativeView, 1288 jint selectionPtr) 1289 { 1290 SelectText* selection = reinterpret_cast<SelectText*>(selectionPtr); 1291 reinterpret_cast<WebView*>(nativeView)->setTextSelection(selection); 1292 } 1293 1294 static jint nativeGetHandleLayerId(JNIEnv *env, jobject obj, jint nativeView, 1295 jint handleIndex, jobject cursorPoint, 1296 jobject textQuad) 1297 { 1298 WebView* webview = reinterpret_cast<WebView*>(nativeView); 1299 SkIPoint nativePoint; 1300 FloatQuad nativeTextQuad; 1301 int layerId = webview->getHandleLayerId((SelectText::HandleId) handleIndex, 1302 nativePoint, nativeTextQuad); 1303 if (cursorPoint) 1304 GraphicsJNI::ipoint_to_jpoint(nativePoint, env, cursorPoint); 1305 if (textQuad) 1306 webview->floatQuadToQuadF(env, nativeTextQuad, textQuad); 1307 return layerId; 1308 } 1309 1310 static void nativeMapLayerRect(JNIEnv *env, jobject obj, jint nativeView, 1311 jint layerId, jobject rect) 1312 { 1313 WebView* webview = reinterpret_cast<WebView*>(nativeView); 1314 SkIRect nativeRect; 1315 GraphicsJNI::jrect_to_irect(env, rect, &nativeRect); 1316 webview->mapLayerRect(layerId, nativeRect); 1317 GraphicsJNI::irect_to_jrect(nativeRect, env, rect); 1318 } 1319 1320 static jint nativeSetHwAccelerated(JNIEnv *env, jobject obj, jint nativeView, 1321 jboolean hwAccelerated) 1322 { 1323 WebView* webview = reinterpret_cast<WebView*>(nativeView); 1324 return webview->setHwAccelerated(hwAccelerated); 1325 } 1326 1327 static void nativeFindMaxVisibleRect(JNIEnv *env, jobject obj, jint nativeView, 1328 jint movingLayerId, jobject visibleContentRect) 1329 { 1330 WebView* webview = reinterpret_cast<WebView*>(nativeView); 1331 SkIRect nativeRect; 1332 GraphicsJNI::jrect_to_irect(env, visibleContentRect, &nativeRect); 1333 webview->findMaxVisibleRect(movingLayerId, nativeRect); 1334 GraphicsJNI::irect_to_jrect(nativeRect, env, visibleContentRect); 1335 } 1336 1337 static bool nativeIsHandleLeft(JNIEnv *env, jobject obj, jint nativeView, 1338 jint handleId) 1339 { 1340 WebView* webview = reinterpret_cast<WebView*>(nativeView); 1341 return webview->isHandleLeft(static_cast<SelectText::HandleId>(handleId)); 1342 } 1343 1344 static bool nativeIsPointVisible(JNIEnv *env, jobject obj, jint nativeView, 1345 jint layerId, jint contentX, jint contentY) 1346 { 1347 WebView* webview = reinterpret_cast<WebView*>(nativeView); 1348 return webview->isPointVisible(layerId, contentX, contentY); 1349 } 1350 1351 /* 1352 * JNI registration 1353 */ 1354 static JNINativeMethod gJavaWebViewMethods[] = { 1355 { "nativeCreate", "(ILjava/lang/String;Z)V", 1356 (void*) nativeCreate }, 1357 { "nativeDestroy", "(I)V", 1358 (void*) nativeDestroy }, 1359 { "nativeDraw", "(Landroid/graphics/Canvas;Landroid/graphics/RectF;II)V", 1360 (void*) nativeDraw }, 1361 { "nativeCreateDrawGLFunction", "(ILandroid/graphics/Rect;Landroid/graphics/Rect;Landroid/graphics/RectF;FI)I", 1362 (void*) nativeCreateDrawGLFunction }, 1363 { "nativeGetDrawGLFunction", "(I)I", 1364 (void*) nativeGetDrawGLFunction }, 1365 { "nativeUpdateDrawGLFunction", "(ILandroid/graphics/Rect;Landroid/graphics/Rect;Landroid/graphics/RectF;F)V", 1366 (void*) nativeUpdateDrawGLFunction }, 1367 { "nativeDumpDisplayTree", "(Ljava/lang/String;)V", 1368 (void*) nativeDumpDisplayTree }, 1369 { "nativeEvaluateLayersAnimations", "(I)Z", 1370 (void*) nativeEvaluateLayersAnimations }, 1371 { "nativeGetSelection", "()Ljava/lang/String;", 1372 (void*) nativeGetSelection }, 1373 { "nativeSetHeightCanMeasure", "(Z)V", 1374 (void*) nativeSetHeightCanMeasure }, 1375 { "nativeSetBaseLayer", "(IIZZI)Z", 1376 (void*) nativeSetBaseLayer }, 1377 { "nativeGetBaseLayer", "(I)I", 1378 (void*) nativeGetBaseLayer }, 1379 { "nativeCopyBaseContentToPicture", "(Landroid/graphics/Picture;)V", 1380 (void*) nativeCopyBaseContentToPicture }, 1381 { "nativeDumpLayerContentToPicture", "(ILjava/lang/String;ILandroid/graphics/Picture;)Z", 1382 (void*) nativeDumpLayerContentToPicture }, 1383 { "nativeHasContent", "()Z", 1384 (void*) nativeHasContent }, 1385 { "nativeDiscardAllTextures", "()V", 1386 (void*) nativeDiscardAllTextures }, 1387 { "nativeTileProfilingStart", "()V", 1388 (void*) nativeTileProfilingStart }, 1389 { "nativeTileProfilingStop", "()F", 1390 (void*) nativeTileProfilingStop }, 1391 { "nativeTileProfilingClear", "()V", 1392 (void*) nativeTileProfilingClear }, 1393 { "nativeTileProfilingNumFrames", "()I", 1394 (void*) nativeTileProfilingNumFrames }, 1395 { "nativeTileProfilingNumTilesInFrame", "(I)I", 1396 (void*) nativeTileProfilingNumTilesInFrame }, 1397 { "nativeTileProfilingGetInt", "(IILjava/lang/String;)I", 1398 (void*) nativeTileProfilingGetInt }, 1399 { "nativeTileProfilingGetFloat", "(IILjava/lang/String;)F", 1400 (void*) nativeTileProfilingGetFloat }, 1401 { "nativeStopGL", "(I)V", 1402 (void*) nativeStopGL }, 1403 { "nativeScrollableLayer", "(IIILandroid/graphics/Rect;Landroid/graphics/Rect;)I", 1404 (void*) nativeScrollableLayer }, 1405 { "nativeScrollLayer", "(IIII)Z", 1406 (void*) nativeScrollLayer }, 1407 { "nativeSetIsScrolling", "(Z)V", 1408 (void*) nativeSetIsScrolling }, 1409 { "nativeUseHardwareAccelSkia", "(Z)V", 1410 (void*) nativeUseHardwareAccelSkia }, 1411 { "nativeGetBackgroundColor", "(I)I", 1412 (void*) nativeGetBackgroundColor }, 1413 { "nativeSetProperty", "(Ljava/lang/String;Ljava/lang/String;)Z", 1414 (void*) nativeSetProperty }, 1415 { "nativeGetProperty", "(Ljava/lang/String;)Ljava/lang/String;", 1416 (void*) nativeGetProperty }, 1417 { "nativeOnTrimMemory", "(I)V", 1418 (void*) nativeOnTrimMemory }, 1419 { "nativeSetPauseDrawing", "(IZ)V", 1420 (void*) nativeSetPauseDrawing }, 1421 { "nativeSetTextSelection", "(II)V", 1422 (void*) nativeSetTextSelection }, 1423 { "nativeGetHandleLayerId", "(IILandroid/graphics/Point;Landroid/webkit/QuadF;)I", 1424 (void*) nativeGetHandleLayerId }, 1425 { "nativeMapLayerRect", "(IILandroid/graphics/Rect;)V", 1426 (void*) nativeMapLayerRect }, 1427 { "nativeSetHwAccelerated", "(IZ)I", 1428 (void*) nativeSetHwAccelerated }, 1429 { "nativeFindMaxVisibleRect", "(IILandroid/graphics/Rect;)V", 1430 (void*) nativeFindMaxVisibleRect }, 1431 { "nativeIsHandleLeft", "(II)Z", 1432 (void*) nativeIsHandleLeft }, 1433 { "nativeIsPointVisible", "(IIII)Z", 1434 (void*) nativeIsPointVisible }, 1435 }; 1436 1437 int registerWebView(JNIEnv* env) 1438 { 1439 jclass clazz = env->FindClass("android/webkit/WebViewClassic"); 1440 ALOG_ASSERT(clazz, "Unable to find class android/webkit/WebViewClassic"); 1441 gWebViewField = env->GetFieldID(clazz, "mNativeClass", "I"); 1442 ALOG_ASSERT(gWebViewField, "Unable to find android/webkit/WebViewClassic.mNativeClass"); 1443 env->DeleteLocalRef(clazz); 1444 1445 return jniRegisterNativeMethods(env, "android/webkit/WebViewClassic", gJavaWebViewMethods, NELEM(gJavaWebViewMethods)); 1446 } 1447 1448 } // namespace android 1449