WebView.cpp revision c8d9e14ba1a7c55e17ac2009bda77dc4da834b1c
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 "Frame.h" 36#include "GLWebViewState.h" 37#include "GraphicsJNI.h" 38#include "HTMLInputElement.h" 39#include "IntPoint.h" 40#include "IntRect.h" 41#include "LayerAndroid.h" 42#include "LayerContent.h" 43#include "Node.h" 44#include "utils/Functor.h" 45#include "private/hwui/DrawGlInfo.h" 46#include "PlatformGraphicsContext.h" 47#include "PlatformString.h" 48#include "ScrollableLayerAndroid.h" 49#include "SelectText.h" 50#include "SkCanvas.h" 51#include "SkDumpCanvas.h" 52#include "SkPicture.h" 53#include "SkRect.h" 54#include "SkTime.h" 55#include "TilesManager.h" 56#include "TransferQueue.h" 57#include "WebCoreJni.h" 58#include "WebRequestContext.h" 59#include "WebViewCore.h" 60#include "android_graphics.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 86namespace android { 87 88static jfieldID gWebViewField; 89 90//------------------------------------- 91 92static 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. 102class WebView 103{ 104public: 105enum FrameCachePermission { 106 DontAllowNewer, 107 AllowNewer 108}; 109 110#define DRAW_EXTRAS_SIZE 2 111enum DrawExtras { // keep this in sync with WebView.java 112 DrawExtrasNone = 0, 113 DrawExtrasSelection = 1, 114 DrawExtrasCursorRing = 2 115}; 116 117struct 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 140WebView(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 208DrawExtra* getDrawExtra(DrawExtras extras) 209{ 210 if (extras == DrawExtrasNone) 211 return 0; 212 return m_extras[extras - 1]; 213} 214 215void stopGL() 216{ 217#if USE(ACCELERATED_COMPOSITING) 218 delete m_glWebViewState; 219 m_glWebViewState = 0; 220#endif 221} 222 223WebViewCore* getWebViewCore() const { 224 return m_viewImpl; 225} 226 227void 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 254int 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 299void 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->updateLayerPositions(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 330int 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 342int 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. 360void 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) 371static 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 402int 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 416void scrollLayer(int layerId, int x, int y) 417{ 418 if (m_glWebViewState) 419 m_glWebViewState->scrollLayer(layerId, x, y); 420} 421 422void setHeightCanMeasure(bool measure) 423{ 424 m_heightCanMeasure = measure; 425} 426 427String getSelection() 428{ 429 SelectText* select = static_cast<SelectText*>( 430 getDrawExtra(WebView::DrawExtrasSelection)); 431 if (select) 432 return select->getText(); 433 return String(); 434} 435 436bool 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 449void setIsScrolling(bool isScrolling) 450{ 451#if USE(ACCELERATED_COMPOSITING) 452 if (m_glWebViewState) 453 m_glWebViewState->setIsScrolling(isScrolling); 454#endif 455} 456 457void 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 467void 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 477void 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) 489static void copyScrollPositionRecursive(const LayerAndroid* from, 490 LayerAndroid* root) 491{ 492 if (!from || !root) 493 return; 494 for (int i = 0; i < from->countChildren(); i++) { 495 const LayerAndroid* l = from->getChild(i); 496 if (l->contentIsScrollable()) { 497 const SkPoint& pos = l->getPosition(); 498 LayerAndroid* match = root->findById(l->uniqueId()); 499 if (match && match->contentIsScrollable()) 500 match->setPosition(pos.fX, pos.fY); 501 } 502 copyScrollPositionRecursive(l, root); 503 } 504} 505#endif 506 507BaseLayerAndroid* getBaseLayer() const { return m_baseLayer; } 508 509bool setBaseLayer(BaseLayerAndroid* newBaseLayer, bool showVisualIndicator, 510 bool isPictureAfterFirstLayout) 511{ 512 bool queueFull = false; 513#if USE(ACCELERATED_COMPOSITING) 514 if (m_glWebViewState) 515 queueFull = m_glWebViewState->setBaseLayer(newBaseLayer, showVisualIndicator, 516 isPictureAfterFirstLayout); 517#endif 518 519#if ENABLE(ANDROID_OVERFLOW_SCROLL) 520 if (newBaseLayer) { 521 // TODO: the below tree position copies are only necessary in software rendering 522 copyScrollPositionRecursive(m_baseLayer, newBaseLayer); 523 } 524#endif 525 SkSafeUnref(m_baseLayer); 526 m_baseLayer = newBaseLayer; 527 528 return queueFull; 529} 530 531void copyBaseContentToPicture(SkPicture* picture) 532{ 533 if (!m_baseLayer || !m_baseLayer->content()) 534 return; 535 LayerContent* content = m_baseLayer->content(); 536 content->draw(picture->beginRecording(content->width(), content->height(), 537 SkPicture::kUsePathBoundsForClip_RecordingFlag)); 538 picture->endRecording(); 539} 540 541bool hasContent() { 542 if (!m_baseLayer || !m_baseLayer->content()) 543 return false; 544 return !m_baseLayer->content()->isEmpty(); 545} 546 547void setFunctor(Functor* functor) { 548 delete m_glDrawFunctor; 549 m_glDrawFunctor = functor; 550} 551 552Functor* getFunctor() { 553 return m_glDrawFunctor; 554} 555 556void setVisibleContentRect(SkRect& visibleContentRect) { 557 m_visibleContentRect = visibleContentRect; 558} 559 560void setDrawExtra(DrawExtra *extra, DrawExtras type) 561{ 562 if (type == DrawExtrasNone) 563 return; 564 DrawExtra* old = m_extras[type - 1]; 565 m_extras[type - 1] = extra; 566 if (old != extra) { 567 delete old; 568 } 569} 570 571void setTextSelection(SelectText *selection) { 572 setDrawExtra(selection, DrawExtrasSelection); 573} 574 575const TransformationMatrix* getLayerTransform(int layerId) { 576 if (layerId != -1 && m_baseLayer) { 577 LayerAndroid* layer = m_baseLayer->findById(layerId); 578 // We need to make sure the drawTransform is up to date as this is 579 // called before a draw() or drawGL() 580 if (layer) { 581 m_baseLayer->updatePositionsRecursive(m_visibleContentRect); 582 return layer->drawTransform(); 583 } 584 } 585 return 0; 586} 587 588int getHandleLayerId(SelectText::HandleId handleId, SkIPoint& cursorPoint, 589 FloatQuad& textBounds) { 590 SelectText* selectText = static_cast<SelectText*>(getDrawExtra(DrawExtrasSelection)); 591 if (!selectText || !m_baseLayer) 592 return -1; 593 int layerId = selectText->caretLayerId(handleId); 594 IntRect cursorRect = selectText->caretRect(handleId); 595 IntRect textRect = selectText->textRect(handleId); 596 // Rects exclude the last pixel on right/bottom. We want only included pixels. 597 cursorPoint.set(cursorRect.x(), cursorRect.maxY() - 1); 598 textRect.setHeight(std::max(1, textRect.height() - 1)); 599 textRect.setWidth(std::max(1, textRect.width() - 1)); 600 textBounds = FloatQuad(textRect); 601 602 const TransformationMatrix* transform = getLayerTransform(layerId); 603 if (transform) { 604 // We're overloading the concept of Rect to be just the two 605 // points (bottom-left and top-right. 606 cursorPoint = transform->mapPoint(cursorPoint); 607 textBounds = transform->mapQuad(textBounds); 608 } 609 return layerId; 610} 611 612void mapLayerRect(int layerId, SkIRect& rect) { 613 const TransformationMatrix* transform = getLayerTransform(layerId); 614 if (transform) 615 rect = transform->mapRect(rect); 616} 617 618void floatQuadToQuadF(JNIEnv* env, const FloatQuad& nativeTextQuad, 619 jobject textQuad) 620{ 621 jobject p1 = env->GetObjectField(textQuad, m_javaGlue.m_quadFP1); 622 jobject p2 = env->GetObjectField(textQuad, m_javaGlue.m_quadFP2); 623 jobject p3 = env->GetObjectField(textQuad, m_javaGlue.m_quadFP3); 624 jobject p4 = env->GetObjectField(textQuad, m_javaGlue.m_quadFP4); 625 GraphicsJNI::point_to_jpointf(nativeTextQuad.p1(), env, p1); 626 GraphicsJNI::point_to_jpointf(nativeTextQuad.p2(), env, p2); 627 GraphicsJNI::point_to_jpointf(nativeTextQuad.p3(), env, p3); 628 GraphicsJNI::point_to_jpointf(nativeTextQuad.p4(), env, p4); 629 env->DeleteLocalRef(p1); 630 env->DeleteLocalRef(p2); 631 env->DeleteLocalRef(p3); 632 env->DeleteLocalRef(p4); 633} 634 635// This is called when WebView switches rendering modes in a more permanent fashion 636// such as when the layer type is set or the view is attached/detached from the window 637int setHwAccelerated(bool hwAccelerated) { 638 if (!m_glWebViewState) 639 return 0; 640 LayerAndroid* root = m_baseLayer; 641 if (root) 642 return root->setHwAccelerated(hwAccelerated); 643 return 0; 644} 645 646void setDrawingPaused(bool isPaused) 647{ 648 m_isDrawingPaused = isPaused; 649 if (m_viewImpl) 650 m_viewImpl->setPrerenderingEnabled(!isPaused); 651} 652 653// Finds the rectangles within world to the left, right, top, and bottom 654// of rect and adds them to rects. If no intersection exists, false is returned. 655static bool findMaskedRects(const FloatRect& world, 656 const FloatRect& rect, Vector<FloatRect>& rects) { 657 if (!world.intersects(rect)) 658 return false; // nothing to subtract 659 660 // left rectangle 661 if (rect.x() > world.x()) 662 rects.append(FloatRect(world.x(), world.y(), 663 rect.x() - world.x(), world.height())); 664 // top rectangle 665 if (rect.y() > world.y()) 666 rects.append(FloatRect(world.x(), world.y(), 667 world.width(), rect.y() - world.y())); 668 // right rectangle 669 if (rect.maxX() < world.maxX()) 670 rects.append(FloatRect(rect.maxX(), world.y(), 671 world.maxX() - rect.maxX(), world.height())); 672 // bottom rectangle 673 if (rect.maxY() < world.maxY()) 674 rects.append(FloatRect(world.x(), rect.maxY(), 675 world.width(), world.maxY() - rect.maxY())); 676 return true; 677} 678 679// Returns false if layerId is a fixed position layer, otherwise 680// all fixed position layer rectangles are subtracted from those within 681// rects. Rects will be modified to contain rectangles that don't include 682// the fixed position layer rectangles. 683static bool findMaskedRectsForLayer(LayerAndroid* layer, 684 Vector<FloatRect>& rects, int layerId) 685{ 686 if (layer->isPositionFixed()) { 687 if (layerId == layer->uniqueId()) 688 return false; 689 FloatRect layerRect = layer->fullContentAreaMapped(); 690 for (int i = rects.size() - 1; i >= 0; i--) 691 if (findMaskedRects(rects[i], layerRect, rects)) 692 rects.remove(i); 693 } 694 695 int childIndex = 0; 696 while (LayerAndroid* child = layer->getChild(childIndex++)) 697 if (!findMaskedRectsForLayer(child, rects, layerId)) 698 return false; 699 700 return true; 701} 702 703// Finds the largest rectangle not masked by any fixed layer. 704void findMaxVisibleRect(int movingLayerId, SkIRect& visibleContentRect) 705{ 706 if (!m_baseLayer) 707 return; 708 709 FloatRect visibleContentFloatRect(visibleContentRect); 710 m_baseLayer->updatePositionsRecursive(visibleContentFloatRect); 711 Vector<FloatRect> rects; 712 rects.append(visibleContentFloatRect); 713 if (findMaskedRectsForLayer(m_baseLayer, rects, movingLayerId)) { 714 float maxSize = 0.0; 715 const FloatRect* largest = 0; 716 for (int i = 0; i < rects.size(); i++) { 717 const FloatRect& rect = rects[i]; 718 float size = rect.width() * rect.height(); 719 if (size > maxSize) { 720 maxSize = size; 721 largest = ▭ 722 } 723 } 724 if (largest) { 725 SkRect largeRect = *largest; 726 largeRect.round(&visibleContentRect); 727 } 728 } 729} 730 731private: // local state for WebView 732 bool m_isDrawingPaused; 733 // private to getFrameCache(); other functions operate in a different thread 734 WebViewCore* m_viewImpl; 735 int m_generation; // associate unique ID with sent kit focus to match with ui 736 // Corresponds to the same-named boolean on the java side. 737 bool m_heightCanMeasure; 738 int m_lastDx; 739 SkMSec m_lastDxTime; 740 DrawExtra* m_extras[DRAW_EXTRAS_SIZE]; 741 BaseLayerAndroid* m_baseLayer; 742 Functor* m_glDrawFunctor; 743#if USE(ACCELERATED_COMPOSITING) 744 GLWebViewState* m_glWebViewState; 745#endif 746 SkRect m_visibleContentRect; 747 bool m_isHighEndGfx; 748}; // end of WebView class 749 750 751/** 752 * This class holds a function pointer and parameters for calling drawGL into a specific 753 * viewport. The pointer to the Functor will be put on a framework display list to be called 754 * when the display list is replayed. 755 */ 756class GLDrawFunctor : Functor { 757 public: 758 GLDrawFunctor(WebView* _wvInstance, 759 int (WebView::*_funcPtr)(WebCore::IntRect&, WebCore::IntRect*, 760 WebCore::IntRect&, int, WebCore::IntRect&, jfloat, jint, bool), 761 WebCore::IntRect _invScreenRect, float _scale, int _extras) { 762 wvInstance = _wvInstance; 763 funcPtr = _funcPtr; 764 invScreenRect = _invScreenRect; 765 scale = _scale; 766 extras = _extras; 767 }; 768 769 status_t operator()(int messageId, void* data) { 770 TRACE_METHOD(); 771 bool shouldDraw = (messageId == uirenderer::DrawGlInfo::kModeDraw); 772 if (shouldDraw) 773 wvInstance->updateRectsForGL(); 774 775 if (invScreenRect.isEmpty()) { 776 // NOOP operation if viewport is empty 777 return 0; 778 } 779 780 WebCore::IntRect inval; 781 int titlebarHeight = screenRect.height() - invScreenRect.height(); 782 783 uirenderer::DrawGlInfo* info = reinterpret_cast<uirenderer::DrawGlInfo*>(data); 784 WebCore::IntRect screenClip(info->clipLeft, info->clipTop, 785 info->clipRight - info->clipLeft, 786 info->clipBottom - info->clipTop); 787 788 WebCore::IntRect localInvScreenRect = invScreenRect; 789 if (info->isLayer) { 790 // When webview is on a layer, we need to use the viewport relative 791 // to the FBO, rather than the screen(which will use invScreenRect). 792 localInvScreenRect.setX(screenClip.x()); 793 localInvScreenRect.setY(info->height - screenClip.y() - screenClip.height()); 794 } 795 // Send the necessary info to the shader. 796 TilesManager::instance()->shader()->setGLDrawInfo(info); 797 798 int returnFlags = (*wvInstance.*funcPtr)(localInvScreenRect, &inval, screenRect, 799 titlebarHeight, screenClip, scale, extras, shouldDraw); 800 if ((returnFlags & uirenderer::DrawGlInfo::kStatusDraw) != 0) { 801 IntRect finalInval; 802 if (inval.isEmpty()) 803 finalInval = screenRect; 804 else { 805 finalInval.setX(screenRect.x() + inval.x()); 806 finalInval.setY(screenRect.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, 2 to request non-drawing functor callback, 0 otherwise 816 ALOGV("returnFlags are %d, shouldDraw %d", returnFlags, shouldDraw); 817 return returnFlags; 818 } 819 void updateScreenRect(WebCore::IntRect& _screenRect) { 820 screenRect = _screenRect; 821 } 822 void updateInvScreenRect(WebCore::IntRect& _invScreenRect) { 823 invScreenRect = _invScreenRect; 824 } 825 void updateScale(float _scale) { 826 scale = _scale; 827 } 828 void updateExtras(jint _extras) { 829 extras = _extras; 830 } 831 private: 832 WebView* wvInstance; 833 int (WebView::*funcPtr)(WebCore::IntRect&, WebCore::IntRect*, 834 WebCore::IntRect&, int, WebCore::IntRect&, float, int, bool); 835 WebCore::IntRect invScreenRect; 836 WebCore::IntRect screenRect; 837 jfloat scale; 838 jint extras; 839}; 840 841/* 842 * Native JNI methods 843 */ 844 845static void nativeCreate(JNIEnv *env, jobject obj, int viewImpl, 846 jstring drawableDir, jboolean isHighEndGfx) 847{ 848 WTF::String dir = jstringToWtfString(env, drawableDir); 849 new WebView(env, obj, viewImpl, dir, isHighEndGfx); 850 // NEED THIS OR SOMETHING LIKE IT! 851 //Release(obj); 852} 853 854static WebCore::IntRect jrect_to_webrect(JNIEnv* env, jobject obj) 855{ 856 if (obj) { 857 int L, T, R, B; 858 GraphicsJNI::get_jrect(env, obj, &L, &T, &R, &B); 859 return WebCore::IntRect(L, T, R - L, B - T); 860 } else 861 return WebCore::IntRect(); 862} 863 864static SkRect jrectf_to_rect(JNIEnv* env, jobject obj) 865{ 866 SkRect rect = SkRect::MakeEmpty(); 867 if (obj) 868 GraphicsJNI::jrectf_to_rect(env, obj, &rect); 869 return rect; 870} 871 872static void nativeDraw(JNIEnv *env, jobject obj, jobject canv, 873 jobject visible, jint color, 874 jint extras) { 875 SkCanvas* canvas = GraphicsJNI::getNativeCanvas(env, canv); 876 WebView* webView = GET_NATIVE_VIEW(env, obj); 877 SkRect visibleContentRect = jrectf_to_rect(env, visible); 878 webView->setVisibleContentRect(visibleContentRect); 879 webView->draw(canvas, color, static_cast<WebView::DrawExtras>(extras)); 880} 881 882static jint nativeCreateDrawGLFunction(JNIEnv *env, jobject obj, jint nativeView, 883 jobject jinvscreenrect, jobject jscreenrect, 884 jobject jvisiblecontentrect, 885 jfloat scale, jint extras) { 886 WebCore::IntRect invScreenRect = jrect_to_webrect(env, jinvscreenrect); 887 WebView *wvInstance = reinterpret_cast<WebView*>(nativeView); 888 SkRect visibleContentRect = jrectf_to_rect(env, jvisiblecontentrect); 889 wvInstance->setVisibleContentRect(visibleContentRect); 890 891 GLDrawFunctor* functor = (GLDrawFunctor*) wvInstance->getFunctor(); 892 if (!functor) { 893 functor = new GLDrawFunctor(wvInstance, &android::WebView::drawGL, 894 invScreenRect, scale, extras); 895 wvInstance->setFunctor((Functor*) functor); 896 } else { 897 functor->updateInvScreenRect(invScreenRect); 898 functor->updateScale(scale); 899 functor->updateExtras(extras); 900 } 901 902 WebCore::IntRect rect = jrect_to_webrect(env, jscreenrect); 903 functor->updateScreenRect(rect); 904 905 return (jint)functor; 906} 907 908static jint nativeGetDrawGLFunction(JNIEnv *env, jobject obj, jint nativeView) { 909 WebView *wvInstance = reinterpret_cast<WebView*>(nativeView); 910 if (!wvInstance) 911 return 0; 912 913 return (jint) wvInstance->getFunctor(); 914} 915 916static void nativeUpdateDrawGLFunction(JNIEnv *env, jobject obj, jint nativeView, 917 jobject jinvscreenrect, jobject jscreenrect, 918 jobject jvisiblecontentrect, jfloat scale) { 919 WebView *wvInstance = reinterpret_cast<WebView*>(nativeView); 920 if (wvInstance) { 921 GLDrawFunctor* functor = (GLDrawFunctor*) wvInstance->getFunctor(); 922 if (functor) { 923 WebCore::IntRect invScreenRect = jrect_to_webrect(env, jinvscreenrect); 924 functor->updateInvScreenRect(invScreenRect); 925 926 SkRect visibleContentRect = jrectf_to_rect(env, jvisiblecontentrect); 927 wvInstance->setVisibleContentRect(visibleContentRect); 928 929 WebCore::IntRect screenRect = jrect_to_webrect(env, jscreenrect); 930 functor->updateScreenRect(screenRect); 931 932 functor->updateScale(scale); 933 } 934 } 935} 936 937static bool nativeEvaluateLayersAnimations(JNIEnv *env, jobject obj, jint nativeView) 938{ 939 // only call in software rendering, initialize and evaluate animations 940#if USE(ACCELERATED_COMPOSITING) 941 BaseLayerAndroid* baseLayer = reinterpret_cast<WebView*>(nativeView)->getBaseLayer(); 942 if (baseLayer) { 943 baseLayer->initAnimations(); 944 return baseLayer->evaluateAnimations(); 945 } 946#endif 947 return false; 948} 949 950static bool nativeSetBaseLayer(JNIEnv *env, jobject obj, jint nativeView, jint layer, 951 jboolean showVisualIndicator, 952 jboolean isPictureAfterFirstLayout) 953{ 954 BaseLayerAndroid* layerImpl = reinterpret_cast<BaseLayerAndroid*>(layer); 955 return reinterpret_cast<WebView*>(nativeView)->setBaseLayer(layerImpl, showVisualIndicator, 956 isPictureAfterFirstLayout); 957} 958 959static BaseLayerAndroid* nativeGetBaseLayer(JNIEnv *env, jobject obj, jint nativeView) 960{ 961 return reinterpret_cast<WebView*>(nativeView)->getBaseLayer(); 962} 963 964static void nativeCopyBaseContentToPicture(JNIEnv *env, jobject obj, jobject pict) 965{ 966 SkPicture* picture = GraphicsJNI::getNativePicture(env, pict); 967 GET_NATIVE_VIEW(env, obj)->copyBaseContentToPicture(picture); 968} 969 970static bool nativeHasContent(JNIEnv *env, jobject obj) 971{ 972 return GET_NATIVE_VIEW(env, obj)->hasContent(); 973} 974 975static void nativeSetHeightCanMeasure(JNIEnv *env, jobject obj, bool measure) 976{ 977 WebView* view = GET_NATIVE_VIEW(env, obj); 978 ALOG_ASSERT(view, "view not set in nativeSetHeightCanMeasure"); 979 view->setHeightCanMeasure(measure); 980} 981 982static void nativeDestroy(JNIEnv *env, jobject obj) 983{ 984 WebView* view = GET_NATIVE_VIEW(env, obj); 985 ALOGD("nativeDestroy view: %p", view); 986 ALOG_ASSERT(view, "view not set in nativeDestroy"); 987 delete view; 988} 989 990static void nativeStopGL(JNIEnv *env, jobject obj) 991{ 992 GET_NATIVE_VIEW(env, obj)->stopGL(); 993} 994 995static jobject nativeGetSelection(JNIEnv *env, jobject obj) 996{ 997 WebView* view = GET_NATIVE_VIEW(env, obj); 998 ALOG_ASSERT(view, "view not set in %s", __FUNCTION__); 999 String selection = view->getSelection(); 1000 return wtfStringToJstring(env, selection); 1001} 1002 1003static void nativeDiscardAllTextures(JNIEnv *env, jobject obj) 1004{ 1005 //discard all textures for debugging/test purposes, but not gl backing memory 1006 bool allTextures = true, deleteGLTextures = false; 1007 TilesManager::instance()->discardTextures(allTextures, deleteGLTextures); 1008} 1009 1010static void nativeTileProfilingStart(JNIEnv *env, jobject obj) 1011{ 1012 TilesManager::instance()->getProfiler()->start(); 1013} 1014 1015static float nativeTileProfilingStop(JNIEnv *env, jobject obj) 1016{ 1017 return TilesManager::instance()->getProfiler()->stop(); 1018} 1019 1020static void nativeTileProfilingClear(JNIEnv *env, jobject obj) 1021{ 1022 TilesManager::instance()->getProfiler()->clear(); 1023} 1024 1025static int nativeTileProfilingNumFrames(JNIEnv *env, jobject obj) 1026{ 1027 return TilesManager::instance()->getProfiler()->numFrames(); 1028} 1029 1030static int nativeTileProfilingNumTilesInFrame(JNIEnv *env, jobject obj, int frame) 1031{ 1032 return TilesManager::instance()->getProfiler()->numTilesInFrame(frame); 1033} 1034 1035static int nativeTileProfilingGetInt(JNIEnv *env, jobject obj, int frame, int tile, jstring jkey) 1036{ 1037 WTF::String key = jstringToWtfString(env, jkey); 1038 TileProfileRecord* record = TilesManager::instance()->getProfiler()->getTile(frame, tile); 1039 1040 if (key == "left") 1041 return record->left; 1042 if (key == "top") 1043 return record->top; 1044 if (key == "right") 1045 return record->right; 1046 if (key == "bottom") 1047 return record->bottom; 1048 if (key == "level") 1049 return record->level; 1050 if (key == "isReady") 1051 return record->isReady ? 1 : 0; 1052 return -1; 1053} 1054 1055static float nativeTileProfilingGetFloat(JNIEnv *env, jobject obj, int frame, int tile, jstring jkey) 1056{ 1057 TileProfileRecord* record = TilesManager::instance()->getProfiler()->getTile(frame, tile); 1058 return record->scale; 1059} 1060 1061#ifdef ANDROID_DUMP_DISPLAY_TREE 1062static void dumpToFile(const char text[], void* file) { 1063 fwrite(text, 1, strlen(text), reinterpret_cast<FILE*>(file)); 1064 fwrite("\n", 1, 1, reinterpret_cast<FILE*>(file)); 1065} 1066#endif 1067 1068// Return true to view invalidate WebView 1069static bool nativeSetProperty(JNIEnv *env, jobject obj, jstring jkey, jstring jvalue) 1070{ 1071 WTF::String key = jstringToWtfString(env, jkey); 1072 WTF::String value = jstringToWtfString(env, jvalue); 1073 if (key == "inverted") { 1074 bool shouldInvert = (value == "true"); 1075 TilesManager::instance()->setInvertedScreen(shouldInvert); 1076 return true; 1077 } 1078 else if (key == "inverted_contrast") { 1079 float contrast = value.toFloat(); 1080 TilesManager::instance()->setInvertedScreenContrast(contrast); 1081 return true; 1082 } 1083 else if (key == "enable_cpu_upload_path") { 1084 TilesManager::instance()->transferQueue()->setTextureUploadType( 1085 value == "true" ? CpuUpload : GpuUpload); 1086 } 1087 else if (key == "use_minimal_memory") { 1088 TilesManager::instance()->setUseMinimalMemory(value == "true"); 1089 } 1090 else if (key == "use_double_buffering") { 1091 TilesManager::instance()->setUseDoubleBuffering(value == "true"); 1092 } 1093 else if (key == "tree_updates") { 1094 TilesManager::instance()->clearContentUpdates(); 1095 } 1096 return false; 1097} 1098 1099static jstring nativeGetProperty(JNIEnv *env, jobject obj, jstring jkey) 1100{ 1101 WTF::String key = jstringToWtfString(env, jkey); 1102 if (key == "tree_updates") { 1103 int updates = TilesManager::instance()->getContentUpdates(); 1104 WTF::String wtfUpdates = WTF::String::number(updates); 1105 return wtfStringToJstring(env, wtfUpdates); 1106 } 1107 return 0; 1108} 1109 1110static void nativeOnTrimMemory(JNIEnv *env, jobject obj, jint level) 1111{ 1112 if (TilesManager::hardwareAccelerationEnabled()) { 1113 // When we got TRIM_MEMORY_MODERATE or TRIM_MEMORY_COMPLETE, we should 1114 // make sure the transfer queue is empty and then abandon the Surface 1115 // Texture to avoid ANR b/c framework may destroy the EGL context. 1116 // Refer to WindowManagerImpl.java for conditions we followed. 1117 TilesManager* tilesManager = TilesManager::instance(); 1118 if ((level >= TRIM_MEMORY_MODERATE 1119 && !tilesManager->highEndGfx()) 1120 || level >= TRIM_MEMORY_COMPLETE) { 1121 ALOGD("OnTrimMemory with EGL Context %p", eglGetCurrentContext()); 1122 tilesManager->cleanupGLResources(); 1123 } 1124 1125 bool freeAllTextures = (level > TRIM_MEMORY_UI_HIDDEN), glTextures = true; 1126 tilesManager->discardTextures(freeAllTextures, glTextures); 1127 } 1128} 1129 1130static void nativeDumpDisplayTree(JNIEnv* env, jobject jwebview, jstring jurl) 1131{ 1132#ifdef ANDROID_DUMP_DISPLAY_TREE 1133 WebView* view = GET_NATIVE_VIEW(env, jwebview); 1134 ALOG_ASSERT(view, "view not set in %s", __FUNCTION__); 1135 1136 if (view && view->getWebViewCore()) { 1137 FILE* file = fopen(DISPLAY_TREE_LOG_FILE, "w"); 1138 if (file) { 1139 SkFormatDumper dumper(dumpToFile, file); 1140 // dump the URL 1141 if (jurl) { 1142 const char* str = env->GetStringUTFChars(jurl, 0); 1143 SkDebugf("Dumping %s to %s\n", str, DISPLAY_TREE_LOG_FILE); 1144 dumpToFile(str, file); 1145 env->ReleaseStringUTFChars(jurl, str); 1146 } 1147 // now dump the display tree 1148 SkDumpCanvas canvas(&dumper); 1149 // this will playback the picture into the canvas, which will 1150 // spew its contents to the dumper 1151 view->draw(&canvas, 0, WebView::DrawExtrasNone); 1152 // we're done with the file now 1153 fwrite("\n", 1, 1, file); 1154 fclose(file); 1155 } 1156#if USE(ACCELERATED_COMPOSITING) 1157 const LayerAndroid* baseLayer = view->getBaseLayer(); 1158 if (baseLayer) { 1159 FILE* file = fopen(LAYERS_TREE_LOG_FILE,"w"); 1160 if (file) { 1161 baseLayer->dumpLayers(file, 0); 1162 fclose(file); 1163 } 1164 } 1165#endif 1166 } 1167#endif 1168} 1169 1170static int nativeScrollableLayer(JNIEnv* env, jobject jwebview, jint nativeView, 1171 jint x, jint y, jobject rect, jobject bounds) 1172{ 1173 WebView* webview = reinterpret_cast<WebView*>(nativeView); 1174 ALOG_ASSERT(webview, "webview not set in %s", __FUNCTION__); 1175 SkIRect nativeRect, nativeBounds; 1176 int id = webview->scrollableLayer(x, y, &nativeRect, &nativeBounds); 1177 if (rect) 1178 GraphicsJNI::irect_to_jrect(nativeRect, env, rect); 1179 if (bounds) 1180 GraphicsJNI::irect_to_jrect(nativeBounds, env, bounds); 1181 return id; 1182} 1183 1184static bool nativeScrollLayer(JNIEnv* env, jobject obj, 1185 jint nativeView, jint layerId, jint x, jint y) 1186{ 1187#if ENABLE(ANDROID_OVERFLOW_SCROLL) 1188 WebView* webview = reinterpret_cast<WebView*>(nativeView); 1189 webview->scrollLayer(layerId, x, y); 1190 1191 //TODO: the below only needed for the SW rendering path 1192 LayerAndroid* baseLayer = webview->getBaseLayer(); 1193 if (!baseLayer) 1194 return false; 1195 LayerAndroid* layer = baseLayer->findById(layerId); 1196 if (!layer || !layer->contentIsScrollable()) 1197 return false; 1198 return static_cast<ScrollableLayerAndroid*>(layer)->scrollTo(x, y); 1199#endif 1200 return false; 1201} 1202 1203static void nativeSetIsScrolling(JNIEnv* env, jobject jwebview, jboolean isScrolling) 1204{ 1205 // TODO: Pass in the native pointer instead 1206 WebView* view = GET_NATIVE_VIEW(env, jwebview); 1207 if (view) 1208 view->setIsScrolling(isScrolling); 1209} 1210 1211static void nativeUseHardwareAccelSkia(JNIEnv*, jobject, jboolean enabled) 1212{ 1213 BaseRenderer::setCurrentRendererType(enabled ? BaseRenderer::Ganesh : BaseRenderer::Raster); 1214} 1215 1216static int nativeGetBackgroundColor(JNIEnv* env, jobject obj, jint nativeView) 1217{ 1218 WebView* view = reinterpret_cast<WebView*>(nativeView); 1219 BaseLayerAndroid* baseLayer = view->getBaseLayer(); 1220 if (baseLayer) { 1221 WebCore::Color color = baseLayer->getBackgroundColor(); 1222 if (color.isValid()) 1223 return SkColorSetARGB(color.alpha(), color.red(), 1224 color.green(), color.blue()); 1225 } 1226 return SK_ColorWHITE; 1227} 1228 1229static void nativeSetPauseDrawing(JNIEnv *env, jobject obj, jint nativeView, 1230 jboolean pause) 1231{ 1232 reinterpret_cast<WebView*>(nativeView)->setDrawingPaused(pause); 1233} 1234 1235static void nativeSetTextSelection(JNIEnv *env, jobject obj, jint nativeView, 1236 jint selectionPtr) 1237{ 1238 SelectText* selection = reinterpret_cast<SelectText*>(selectionPtr); 1239 reinterpret_cast<WebView*>(nativeView)->setTextSelection(selection); 1240} 1241 1242static jint nativeGetHandleLayerId(JNIEnv *env, jobject obj, jint nativeView, 1243 jint handleIndex, jobject cursorPoint, 1244 jobject textQuad) 1245{ 1246 WebView* webview = reinterpret_cast<WebView*>(nativeView); 1247 SkIPoint nativePoint; 1248 FloatQuad nativeTextQuad; 1249 int layerId = webview->getHandleLayerId((SelectText::HandleId) handleIndex, 1250 nativePoint, nativeTextQuad); 1251 if (cursorPoint) 1252 GraphicsJNI::ipoint_to_jpoint(nativePoint, env, cursorPoint); 1253 if (textQuad) 1254 webview->floatQuadToQuadF(env, nativeTextQuad, textQuad); 1255 return layerId; 1256} 1257 1258static void nativeMapLayerRect(JNIEnv *env, jobject obj, jint nativeView, 1259 jint layerId, jobject rect) 1260{ 1261 WebView* webview = reinterpret_cast<WebView*>(nativeView); 1262 SkIRect nativeRect; 1263 GraphicsJNI::jrect_to_irect(env, rect, &nativeRect); 1264 webview->mapLayerRect(layerId, nativeRect); 1265 GraphicsJNI::irect_to_jrect(nativeRect, env, rect); 1266} 1267 1268static jint nativeSetHwAccelerated(JNIEnv *env, jobject obj, jint nativeView, 1269 jboolean hwAccelerated) 1270{ 1271 WebView* webview = reinterpret_cast<WebView*>(nativeView); 1272 return webview->setHwAccelerated(hwAccelerated); 1273} 1274 1275static void nativeFindMaxVisibleRect(JNIEnv *env, jobject obj, jint nativeView, 1276 jint movingLayerId, jobject visibleContentRect) 1277{ 1278 WebView* webview = reinterpret_cast<WebView*>(nativeView); 1279 SkIRect nativeRect; 1280 GraphicsJNI::jrect_to_irect(env, visibleContentRect, &nativeRect); 1281 webview->findMaxVisibleRect(movingLayerId, nativeRect); 1282 GraphicsJNI::irect_to_jrect(nativeRect, env, visibleContentRect); 1283} 1284 1285/* 1286 * JNI registration 1287 */ 1288static JNINativeMethod gJavaWebViewMethods[] = { 1289 { "nativeCreate", "(ILjava/lang/String;Z)V", 1290 (void*) nativeCreate }, 1291 { "nativeDestroy", "()V", 1292 (void*) nativeDestroy }, 1293 { "nativeDraw", "(Landroid/graphics/Canvas;Landroid/graphics/RectF;II)V", 1294 (void*) nativeDraw }, 1295 { "nativeCreateDrawGLFunction", "(ILandroid/graphics/Rect;Landroid/graphics/Rect;Landroid/graphics/RectF;FI)I", 1296 (void*) nativeCreateDrawGLFunction }, 1297 { "nativeGetDrawGLFunction", "(I)I", 1298 (void*) nativeGetDrawGLFunction }, 1299 { "nativeUpdateDrawGLFunction", "(ILandroid/graphics/Rect;Landroid/graphics/Rect;Landroid/graphics/RectF;F)V", 1300 (void*) nativeUpdateDrawGLFunction }, 1301 { "nativeDumpDisplayTree", "(Ljava/lang/String;)V", 1302 (void*) nativeDumpDisplayTree }, 1303 { "nativeEvaluateLayersAnimations", "(I)Z", 1304 (void*) nativeEvaluateLayersAnimations }, 1305 { "nativeGetSelection", "()Ljava/lang/String;", 1306 (void*) nativeGetSelection }, 1307 { "nativeSetHeightCanMeasure", "(Z)V", 1308 (void*) nativeSetHeightCanMeasure }, 1309 { "nativeSetBaseLayer", "(IIZZ)Z", 1310 (void*) nativeSetBaseLayer }, 1311 { "nativeGetBaseLayer", "(I)I", 1312 (void*) nativeGetBaseLayer }, 1313 { "nativeCopyBaseContentToPicture", "(Landroid/graphics/Picture;)V", 1314 (void*) nativeCopyBaseContentToPicture }, 1315 { "nativeHasContent", "()Z", 1316 (void*) nativeHasContent }, 1317 { "nativeDiscardAllTextures", "()V", 1318 (void*) nativeDiscardAllTextures }, 1319 { "nativeTileProfilingStart", "()V", 1320 (void*) nativeTileProfilingStart }, 1321 { "nativeTileProfilingStop", "()F", 1322 (void*) nativeTileProfilingStop }, 1323 { "nativeTileProfilingClear", "()V", 1324 (void*) nativeTileProfilingClear }, 1325 { "nativeTileProfilingNumFrames", "()I", 1326 (void*) nativeTileProfilingNumFrames }, 1327 { "nativeTileProfilingNumTilesInFrame", "(I)I", 1328 (void*) nativeTileProfilingNumTilesInFrame }, 1329 { "nativeTileProfilingGetInt", "(IILjava/lang/String;)I", 1330 (void*) nativeTileProfilingGetInt }, 1331 { "nativeTileProfilingGetFloat", "(IILjava/lang/String;)F", 1332 (void*) nativeTileProfilingGetFloat }, 1333 { "nativeStopGL", "()V", 1334 (void*) nativeStopGL }, 1335 { "nativeScrollableLayer", "(IIILandroid/graphics/Rect;Landroid/graphics/Rect;)I", 1336 (void*) nativeScrollableLayer }, 1337 { "nativeScrollLayer", "(IIII)Z", 1338 (void*) nativeScrollLayer }, 1339 { "nativeSetIsScrolling", "(Z)V", 1340 (void*) nativeSetIsScrolling }, 1341 { "nativeUseHardwareAccelSkia", "(Z)V", 1342 (void*) nativeUseHardwareAccelSkia }, 1343 { "nativeGetBackgroundColor", "(I)I", 1344 (void*) nativeGetBackgroundColor }, 1345 { "nativeSetProperty", "(Ljava/lang/String;Ljava/lang/String;)Z", 1346 (void*) nativeSetProperty }, 1347 { "nativeGetProperty", "(Ljava/lang/String;)Ljava/lang/String;", 1348 (void*) nativeGetProperty }, 1349 { "nativeOnTrimMemory", "(I)V", 1350 (void*) nativeOnTrimMemory }, 1351 { "nativeSetPauseDrawing", "(IZ)V", 1352 (void*) nativeSetPauseDrawing }, 1353 { "nativeSetTextSelection", "(II)V", 1354 (void*) nativeSetTextSelection }, 1355 { "nativeGetHandleLayerId", "(IILandroid/graphics/Point;Landroid/webkit/QuadF;)I", 1356 (void*) nativeGetHandleLayerId }, 1357 { "nativeMapLayerRect", "(IILandroid/graphics/Rect;)V", 1358 (void*) nativeMapLayerRect }, 1359 { "nativeSetHwAccelerated", "(IZ)I", 1360 (void*) nativeSetHwAccelerated }, 1361 { "nativeFindMaxVisibleRect", "(IILandroid/graphics/Rect;)V", 1362 (void*) nativeFindMaxVisibleRect }, 1363}; 1364 1365int registerWebView(JNIEnv* env) 1366{ 1367 jclass clazz = env->FindClass("android/webkit/WebViewClassic"); 1368 ALOG_ASSERT(clazz, "Unable to find class android/webkit/WebViewClassic"); 1369 gWebViewField = env->GetFieldID(clazz, "mNativeClass", "I"); 1370 ALOG_ASSERT(gWebViewField, "Unable to find android/webkit/WebViewClassic.mNativeClass"); 1371 env->DeleteLocalRef(clazz); 1372 1373 return jniRegisterNativeMethods(env, "android/webkit/WebViewClassic", gJavaWebViewMethods, NELEM(gJavaWebViewMethods)); 1374} 1375 1376} // namespace android 1377