Home | History | Annotate | Download | only in nav
      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 = &rect;
    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 #ifdef ANDROID_DUMP_DISPLAY_TREE
   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