WebView.cpp revision 296d05c7bd54360261dedc8d387a7bf9f52ca41b
1/*
2 * Copyright 2007, The Android Open Source Project
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 *  * Redistributions of source code must retain the above copyright
8 *    notice, this list of conditions and the following disclaimer.
9 *  * Redistributions in binary form must reproduce the above copyright
10 *    notice, this list of conditions and the following disclaimer in the
11 *    documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#define LOG_TAG "webviewglue"
27
28#include "config.h"
29
30#include "AndroidAnimation.h"
31#include "AndroidLog.h"
32#include "BaseLayerAndroid.h"
33#include "DrawExtra.h"
34#include "Frame.h"
35#include "GraphicsJNI.h"
36#include "HTMLInputElement.h"
37#include "IntPoint.h"
38#include "IntRect.h"
39#include "LayerAndroid.h"
40#include "Node.h"
41#include "utils/Functor.h"
42#include "private/hwui/DrawGlInfo.h"
43#include "PlatformGraphicsContext.h"
44#include "PlatformString.h"
45#include "ScrollableLayerAndroid.h"
46#include "SelectText.h"
47#include "SkCanvas.h"
48#include "SkDumpCanvas.h"
49#include "SkPicture.h"
50#include "SkRect.h"
51#include "SkTime.h"
52#include "TilesManager.h"
53#include "WebCoreJni.h"
54#include "WebRequestContext.h"
55#include "WebViewCore.h"
56#include "android_graphics.h"
57
58#ifdef GET_NATIVE_VIEW
59#undef GET_NATIVE_VIEW
60#endif
61
62#define GET_NATIVE_VIEW(env, obj) ((WebView*)env->GetIntField(obj, gWebViewField))
63
64#include <JNIUtility.h>
65#include <JNIHelp.h>
66#include <jni.h>
67#include <androidfw/KeycodeLabels.h>
68#include <wtf/text/AtomicString.h>
69#include <wtf/text/CString.h>
70
71// Free as much as we possible can
72#define TRIM_MEMORY_COMPLETE 80
73// Free a lot (all textures gone)
74#define TRIM_MEMORY_MODERATE 60
75// More moderate free (keep bare minimum to restore quickly-ish - possibly clear all textures)
76#define TRIM_MEMORY_BACKGROUND 40
77// Moderate free (clear cached tiles, keep visible ones)
78#define TRIM_MEMORY_UI_HIDDEN 20
79// Duration to show the pressed cursor ring
80#define PRESSED_STATE_DURATION 400
81
82namespace android {
83
84static jfieldID gWebViewField;
85
86//-------------------------------------
87
88static jmethodID GetJMethod(JNIEnv* env, jclass clazz, const char name[], const char signature[])
89{
90    jmethodID m = env->GetMethodID(clazz, name, signature);
91    ALOG_ASSERT(m, "Could not find method %s", name);
92    return m;
93}
94
95//-------------------------------------
96// This class provides JNI for making calls into native code from the UI side
97// of the multi-threaded WebView.
98class WebView
99{
100public:
101enum FrameCachePermission {
102    DontAllowNewer,
103    AllowNewer
104};
105
106#define DRAW_EXTRAS_SIZE 2
107enum DrawExtras { // keep this in sync with WebView.java
108    DrawExtrasNone = 0,
109    DrawExtrasSelection = 1,
110    DrawExtrasCursorRing = 2
111};
112
113struct JavaGlue {
114    jweak       m_obj;
115    jmethodID   m_scrollBy;
116    jmethodID   m_getScaledMaxXScroll;
117    jmethodID   m_getScaledMaxYScroll;
118    jmethodID   m_getVisibleRect;
119    jmethodID   m_viewInvalidate;
120    jmethodID   m_viewInvalidateRect;
121    jmethodID   m_postInvalidateDelayed;
122    jmethodID   m_pageSwapCallback;
123    jfieldID    m_rectLeft;
124    jfieldID    m_rectTop;
125    jmethodID   m_rectWidth;
126    jmethodID   m_rectHeight;
127    AutoJObject object(JNIEnv* env) {
128        return getRealObject(env, m_obj);
129    }
130} m_javaGlue;
131
132WebView(JNIEnv* env, jobject javaWebView, int viewImpl, WTF::String drawableDir,
133        bool isHighEndGfx)
134    : m_isHighEndGfx(isHighEndGfx)
135{
136    memset(m_extras, 0, DRAW_EXTRAS_SIZE * sizeof(DrawExtra*));
137    jclass clazz = env->FindClass("android/webkit/WebViewClassic");
138    m_javaGlue.m_obj = env->NewWeakGlobalRef(javaWebView);
139    m_javaGlue.m_scrollBy = GetJMethod(env, clazz, "setContentScrollBy", "(IIZ)Z");
140    m_javaGlue.m_getScaledMaxXScroll = GetJMethod(env, clazz, "getScaledMaxXScroll", "()I");
141    m_javaGlue.m_getScaledMaxYScroll = GetJMethod(env, clazz, "getScaledMaxYScroll", "()I");
142    m_javaGlue.m_getVisibleRect = GetJMethod(env, clazz, "sendOurVisibleRect", "()Landroid/graphics/Rect;");
143    m_javaGlue.m_viewInvalidate = GetJMethod(env, clazz, "viewInvalidate", "()V");
144    m_javaGlue.m_viewInvalidateRect = GetJMethod(env, clazz, "viewInvalidate", "(IIII)V");
145    m_javaGlue.m_postInvalidateDelayed = GetJMethod(env, clazz,
146        "viewInvalidateDelayed", "(JIIII)V");
147    m_javaGlue.m_pageSwapCallback = GetJMethod(env, clazz, "pageSwapCallback", "(Z)V");
148    env->DeleteLocalRef(clazz);
149
150    jclass rectClass = env->FindClass("android/graphics/Rect");
151    ALOG_ASSERT(rectClass, "Could not find Rect class");
152    m_javaGlue.m_rectLeft = env->GetFieldID(rectClass, "left", "I");
153    m_javaGlue.m_rectTop = env->GetFieldID(rectClass, "top", "I");
154    m_javaGlue.m_rectWidth = GetJMethod(env, rectClass, "width", "()I");
155    m_javaGlue.m_rectHeight = GetJMethod(env, rectClass, "height", "()I");
156    env->DeleteLocalRef(rectClass);
157
158    env->SetIntField(javaWebView, gWebViewField, (jint)this);
159    m_viewImpl = (WebViewCore*) viewImpl;
160    m_generation = 0;
161    m_heightCanMeasure = false;
162    m_lastDx = 0;
163    m_lastDxTime = 0;
164    m_baseLayer = 0;
165    m_glDrawFunctor = 0;
166    m_isDrawingPaused = false;
167#if USE(ACCELERATED_COMPOSITING)
168    m_glWebViewState = 0;
169#endif
170}
171
172~WebView()
173{
174    if (m_javaGlue.m_obj)
175    {
176        JNIEnv* env = JSC::Bindings::getJNIEnv();
177        env->DeleteWeakGlobalRef(m_javaGlue.m_obj);
178        m_javaGlue.m_obj = 0;
179    }
180#if USE(ACCELERATED_COMPOSITING)
181    // We must remove the m_glWebViewState prior to deleting m_baseLayer. If we
182    // do not remove it here, we risk having BaseTiles trying to paint using a
183    // deallocated base layer.
184    stopGL();
185#endif
186    SkSafeUnref(m_baseLayer);
187    delete m_glDrawFunctor;
188    for (int i = 0; i < DRAW_EXTRAS_SIZE; i++)
189        delete m_extras[i];
190}
191
192DrawExtra* getDrawExtra(DrawExtras extras)
193{
194    if (extras == DrawExtrasNone)
195        return 0;
196    return m_extras[extras - 1];
197}
198
199void stopGL()
200{
201#if USE(ACCELERATED_COMPOSITING)
202    delete m_glWebViewState;
203    m_glWebViewState = 0;
204#endif
205}
206
207WebViewCore* getWebViewCore() const {
208    return m_viewImpl;
209}
210
211void scrollRectOnScreen(const IntRect& rect)
212{
213    if (rect.isEmpty())
214        return;
215    int dx = 0;
216    int left = rect.x();
217    int right = rect.maxX();
218    if (left < m_visibleRect.fLeft)
219        dx = left - m_visibleRect.fLeft;
220    // Only scroll right if the entire width can fit on screen.
221    else if (right > m_visibleRect.fRight
222            && right - left < m_visibleRect.width())
223        dx = right - m_visibleRect.fRight;
224    int dy = 0;
225    int top = rect.y();
226    int bottom = rect.maxY();
227    if (top < m_visibleRect.fTop)
228        dy = top - m_visibleRect.fTop;
229    // Only scroll down if the entire height can fit on screen
230    else if (bottom > m_visibleRect.fBottom
231            && bottom - top < m_visibleRect.height())
232        dy = bottom - m_visibleRect.fBottom;
233    if ((dx|dy) == 0 || !scrollBy(dx, dy))
234        return;
235    viewInvalidate();
236}
237
238bool drawGL(WebCore::IntRect& viewRect, WebCore::IntRect* invalRect,
239        WebCore::IntRect& webViewRect, int titleBarHeight,
240        WebCore::IntRect& clip, float scale, int extras)
241{
242#if USE(ACCELERATED_COMPOSITING)
243    if (!m_baseLayer)
244        return false;
245
246    if (!m_glWebViewState) {
247        TilesManager::instance()->setHighEndGfx(m_isHighEndGfx);
248        m_glWebViewState = new GLWebViewState();
249        if (m_baseLayer->content()) {
250            SkRegion region;
251            SkIRect rect;
252            rect.set(0, 0, m_baseLayer->content()->width(), m_baseLayer->content()->height());
253            region.setRect(rect);
254            m_baseLayer->markAsDirty(region);
255            m_glWebViewState->setBaseLayer(m_baseLayer, false, true);
256        }
257    }
258
259    DrawExtra* extra = getDrawExtra((DrawExtras) extras);
260
261    m_glWebViewState->glExtras()->setDrawExtra(extra);
262
263    // Make sure we have valid coordinates. We might not have valid coords
264    // if the zoom manager is still initializing. We will be redrawn
265    // once the correct scale is set
266    if (!m_visibleRect.isFinite())
267        return false;
268    bool treesSwapped = false;
269    bool newTreeHasAnim = false;
270    bool ret = m_glWebViewState->drawGL(viewRect, m_visibleRect, invalRect,
271                                        webViewRect, titleBarHeight, clip, scale,
272                                        &treesSwapped, &newTreeHasAnim);
273    if (treesSwapped) {
274        ALOG_ASSERT(m_javaGlue.m_obj, "A java object was not associated with this native WebView!");
275        JNIEnv* env = JSC::Bindings::getJNIEnv();
276        AutoJObject javaObject = m_javaGlue.object(env);
277        if (javaObject.get()) {
278            env->CallVoidMethod(javaObject.get(), m_javaGlue.m_pageSwapCallback, newTreeHasAnim);
279            checkException(env);
280        }
281    }
282    if (ret)
283        return !m_isDrawingPaused;
284#endif
285    return false;
286}
287
288PictureSet* draw(SkCanvas* canvas, SkColor bgColor, DrawExtras extras, bool split)
289{
290    PictureSet* ret = 0;
291    if (!m_baseLayer) {
292        canvas->drawColor(bgColor);
293        return ret;
294    }
295
296    // draw the content of the base layer first
297    PictureSet* content = m_baseLayer->content();
298    int sc = canvas->save(SkCanvas::kClip_SaveFlag);
299    canvas->clipRect(SkRect::MakeLTRB(0, 0, content->width(),
300                content->height()), SkRegion::kDifference_Op);
301    canvas->drawColor(bgColor);
302    canvas->restoreToCount(sc);
303    if (content->draw(canvas))
304        ret = split ? new PictureSet(*content) : 0;
305
306    DrawExtra* extra = getDrawExtra(extras);
307    if (extra)
308        extra->draw(canvas, 0);
309
310#if USE(ACCELERATED_COMPOSITING)
311    LayerAndroid* compositeLayer = compositeRoot();
312    if (compositeLayer) {
313        // call this to be sure we've adjusted for any scrolling or animations
314        // before we actually draw
315        compositeLayer->updateLayerPositions(m_visibleRect);
316        compositeLayer->updatePositions();
317        // We have to set the canvas' matrix on the base layer
318        // (to have fixed layers work as intended)
319        SkAutoCanvasRestore restore(canvas, true);
320        m_baseLayer->setMatrix(canvas->getTotalMatrix());
321        canvas->resetMatrix();
322        m_baseLayer->draw(canvas, extra);
323    }
324    if (extra) {
325        IntRect dummy; // inval area, unused for now
326        extra->drawLegacy(canvas, compositeLayer, &dummy);
327    }
328#endif
329    return ret;
330}
331
332int getScaledMaxXScroll()
333{
334    ALOG_ASSERT(m_javaGlue.m_obj, "A java object was not associated with this native WebView!");
335    JNIEnv* env = JSC::Bindings::getJNIEnv();
336    AutoJObject javaObject = m_javaGlue.object(env);
337    if (!javaObject.get())
338        return 0;
339    int result = env->CallIntMethod(javaObject.get(), m_javaGlue.m_getScaledMaxXScroll);
340    checkException(env);
341    return result;
342}
343
344int getScaledMaxYScroll()
345{
346    ALOG_ASSERT(m_javaGlue.m_obj, "A java object was not associated with this native WebView!");
347    JNIEnv* env = JSC::Bindings::getJNIEnv();
348    AutoJObject javaObject = m_javaGlue.object(env);
349    if (!javaObject.get())
350        return 0;
351    int result = env->CallIntMethod(javaObject.get(), m_javaGlue.m_getScaledMaxYScroll);
352    checkException(env);
353    return result;
354}
355
356IntRect getVisibleRect()
357{
358    IntRect rect;
359    ALOG_ASSERT(m_javaGlue.m_obj, "A java object was not associated with this native WebView!");
360    JNIEnv* env = JSC::Bindings::getJNIEnv();
361    AutoJObject javaObject = m_javaGlue.object(env);
362    if (!javaObject.get())
363        return rect;
364    jobject jRect = env->CallObjectMethod(javaObject.get(), m_javaGlue.m_getVisibleRect);
365    checkException(env);
366    rect.setX(env->GetIntField(jRect, m_javaGlue.m_rectLeft));
367    checkException(env);
368    rect.setY(env->GetIntField(jRect, m_javaGlue.m_rectTop));
369    checkException(env);
370    rect.setWidth(env->CallIntMethod(jRect, m_javaGlue.m_rectWidth));
371    checkException(env);
372    rect.setHeight(env->CallIntMethod(jRect, m_javaGlue.m_rectHeight));
373    checkException(env);
374    env->DeleteLocalRef(jRect);
375    checkException(env);
376    return rect;
377}
378
379#if USE(ACCELERATED_COMPOSITING)
380static const ScrollableLayerAndroid* findScrollableLayer(
381    const LayerAndroid* parent, int x, int y, SkIRect* foundBounds) {
382    SkRect bounds;
383    parent->bounds(&bounds);
384    // Check the parent bounds first; this will clip to within a masking layer's
385    // bounds.
386    if (parent->masksToBounds() && !bounds.contains(x, y))
387        return 0;
388    // Move the hit test local to parent.
389    x -= bounds.fLeft;
390    y -= bounds.fTop;
391    int count = parent->countChildren();
392    while (count--) {
393        const LayerAndroid* child = parent->getChild(count);
394        const ScrollableLayerAndroid* result = findScrollableLayer(child, x, y,
395            foundBounds);
396        if (result) {
397            foundBounds->offset(bounds.fLeft, bounds.fTop);
398            if (parent->masksToBounds()) {
399                if (bounds.width() < foundBounds->width())
400                    foundBounds->fRight = foundBounds->fLeft + bounds.width();
401                if (bounds.height() < foundBounds->height())
402                    foundBounds->fBottom = foundBounds->fTop + bounds.height();
403            }
404            return result;
405        }
406    }
407    if (parent->contentIsScrollable()) {
408        foundBounds->set(0, 0, bounds.width(), bounds.height());
409        return static_cast<const ScrollableLayerAndroid*>(parent);
410    }
411    return 0;
412}
413#endif
414
415int scrollableLayer(int x, int y, SkIRect* layerRect, SkIRect* bounds)
416{
417#if USE(ACCELERATED_COMPOSITING)
418    const LayerAndroid* layerRoot = compositeRoot();
419    if (!layerRoot)
420        return 0;
421    const ScrollableLayerAndroid* result = findScrollableLayer(layerRoot, x, y,
422        bounds);
423    if (result) {
424        result->getScrollRect(layerRect);
425        return result->uniqueId();
426    }
427#endif
428    return 0;
429}
430
431void scrollLayer(int layerId, int x, int y)
432{
433    if (m_glWebViewState)
434        m_glWebViewState->scrollLayer(layerId, x, y);
435}
436
437void setHeightCanMeasure(bool measure)
438{
439    m_heightCanMeasure = measure;
440}
441
442String getSelection()
443{
444    SelectText* select = static_cast<SelectText*>(
445            getDrawExtra(WebView::DrawExtrasSelection));
446    if (select)
447        return select->getText();
448    return String();
449}
450
451bool scrollBy(int dx, int dy)
452{
453    ALOG_ASSERT(m_javaGlue.m_obj, "A java object was not associated with this native WebView!");
454
455    JNIEnv* env = JSC::Bindings::getJNIEnv();
456    AutoJObject javaObject = m_javaGlue.object(env);
457    if (!javaObject.get())
458        return false;
459    bool result = env->CallBooleanMethod(javaObject.get(), m_javaGlue.m_scrollBy, dx, dy, true);
460    checkException(env);
461    return result;
462}
463
464void setIsScrolling(bool isScrolling)
465{
466#if USE(ACCELERATED_COMPOSITING)
467    if (m_glWebViewState)
468        m_glWebViewState->setIsScrolling(isScrolling);
469#endif
470}
471
472void viewInvalidate()
473{
474    JNIEnv* env = JSC::Bindings::getJNIEnv();
475    AutoJObject javaObject = m_javaGlue.object(env);
476    if (!javaObject.get())
477        return;
478    env->CallVoidMethod(javaObject.get(), m_javaGlue.m_viewInvalidate);
479    checkException(env);
480}
481
482void viewInvalidateRect(int l, int t, int r, int b)
483{
484    JNIEnv* env = JSC::Bindings::getJNIEnv();
485    AutoJObject javaObject = m_javaGlue.object(env);
486    if (!javaObject.get())
487        return;
488    env->CallVoidMethod(javaObject.get(), m_javaGlue.m_viewInvalidateRect, l, r, t, b);
489    checkException(env);
490}
491
492void postInvalidateDelayed(int64_t delay, const WebCore::IntRect& bounds)
493{
494    JNIEnv* env = JSC::Bindings::getJNIEnv();
495    AutoJObject javaObject = m_javaGlue.object(env);
496    if (!javaObject.get())
497        return;
498    env->CallVoidMethod(javaObject.get(), m_javaGlue.m_postInvalidateDelayed,
499        delay, bounds.x(), bounds.y(), bounds.maxX(), bounds.maxY());
500    checkException(env);
501}
502
503LayerAndroid* compositeRoot() const
504{
505    ALOG_ASSERT(!m_baseLayer || m_baseLayer->countChildren() == 1,
506            "base layer can't have more than one child %s", __FUNCTION__);
507    if (m_baseLayer && m_baseLayer->countChildren() == 1)
508        return static_cast<LayerAndroid*>(m_baseLayer->getChild(0));
509    else
510        return 0;
511}
512
513#if ENABLE(ANDROID_OVERFLOW_SCROLL)
514static void copyScrollPositionRecursive(const LayerAndroid* from,
515                                        LayerAndroid* root)
516{
517    if (!from || !root)
518        return;
519    for (int i = 0; i < from->countChildren(); i++) {
520        const LayerAndroid* l = from->getChild(i);
521        if (l->contentIsScrollable()) {
522            const SkPoint& pos = l->getPosition();
523            LayerAndroid* match = root->findById(l->uniqueId());
524            if (match && match->contentIsScrollable())
525                match->setPosition(pos.fX, pos.fY);
526        }
527        copyScrollPositionRecursive(l, root);
528    }
529}
530#endif
531
532bool setBaseLayer(BaseLayerAndroid* layer, SkRegion& inval, bool showVisualIndicator,
533                  bool isPictureAfterFirstLayout)
534{
535    bool queueFull = false;
536#if USE(ACCELERATED_COMPOSITING)
537    if (m_glWebViewState) {
538        if (layer)
539            layer->markAsDirty(inval);
540        queueFull = m_glWebViewState->setBaseLayer(layer, showVisualIndicator,
541                                                   isPictureAfterFirstLayout);
542    }
543#endif
544
545#if ENABLE(ANDROID_OVERFLOW_SCROLL)
546    if (layer) {
547        // TODO: the below tree copies are only necessary in software rendering
548        LayerAndroid* newCompositeRoot = static_cast<LayerAndroid*>(layer->getChild(0));
549        copyScrollPositionRecursive(compositeRoot(), newCompositeRoot);
550    }
551#endif
552    SkSafeUnref(m_baseLayer);
553    m_baseLayer = layer;
554
555    return queueFull;
556}
557
558void replaceBaseContent(PictureSet* set)
559{
560    if (!m_baseLayer)
561        return;
562    m_baseLayer->setContent(*set);
563    delete set;
564}
565
566void copyBaseContentToPicture(SkPicture* picture)
567{
568    if (!m_baseLayer)
569        return;
570    PictureSet* content = m_baseLayer->content();
571    m_baseLayer->drawCanvas(picture->beginRecording(content->width(), content->height(),
572            SkPicture::kUsePathBoundsForClip_RecordingFlag));
573    picture->endRecording();
574}
575
576bool hasContent() {
577    if (!m_baseLayer)
578        return false;
579    return !m_baseLayer->content()->isEmpty();
580}
581
582void setFunctor(Functor* functor) {
583    delete m_glDrawFunctor;
584    m_glDrawFunctor = functor;
585}
586
587Functor* getFunctor() {
588    return m_glDrawFunctor;
589}
590
591BaseLayerAndroid* getBaseLayer() {
592    return m_baseLayer;
593}
594
595void setVisibleRect(SkRect& visibleRect) {
596    m_visibleRect = visibleRect;
597}
598
599void setDrawExtra(DrawExtra *extra, DrawExtras type)
600{
601    if (type == DrawExtrasNone)
602        return;
603    DrawExtra* old = m_extras[type - 1];
604    m_extras[type - 1] = extra;
605    if (old != extra) {
606        delete old;
607    }
608}
609
610void setTextSelection(SelectText *selection) {
611    setDrawExtra(selection, DrawExtrasSelection);
612}
613
614int getHandleLayerId(SelectText::HandleId handleId, SkIRect& cursorRect) {
615    SelectText* selectText = static_cast<SelectText*>(getDrawExtra(DrawExtrasSelection));
616    if (!selectText || !m_baseLayer)
617        return -1;
618    int layerId = selectText->caretLayerId(handleId);
619    IntRect rect = selectText->caretRect(handleId);
620    if (layerId != -1) {
621        // We need to make sure the drawTransform is up to date as this is
622        // called before a draw() or drawGL()
623        m_baseLayer->updateLayerPositions(m_visibleRect);
624        LayerAndroid* root = compositeRoot();
625        LayerAndroid* layer = root ? root->findById(layerId) : 0;
626        if (layer && layer->drawTransform())
627            rect = layer->drawTransform()->mapRect(rect);
628    }
629    cursorRect.set(rect.x(), rect.y(), rect.maxX(), rect.maxY());
630    return layerId;
631}
632
633    bool m_isDrawingPaused;
634private: // local state for WebView
635    // private to getFrameCache(); other functions operate in a different thread
636    WebViewCore* m_viewImpl;
637    int m_generation; // associate unique ID with sent kit focus to match with ui
638    // Corresponds to the same-named boolean on the java side.
639    bool m_heightCanMeasure;
640    int m_lastDx;
641    SkMSec m_lastDxTime;
642    DrawExtra* m_extras[DRAW_EXTRAS_SIZE];
643    BaseLayerAndroid* m_baseLayer;
644    Functor* m_glDrawFunctor;
645#if USE(ACCELERATED_COMPOSITING)
646    GLWebViewState* m_glWebViewState;
647#endif
648    SkRect m_visibleRect;
649    bool m_isHighEndGfx;
650}; // end of WebView class
651
652
653/**
654 * This class holds a function pointer and parameters for calling drawGL into a specific
655 * viewport. The pointer to the Functor will be put on a framework display list to be called
656 * when the display list is replayed.
657 */
658class GLDrawFunctor : Functor {
659    public:
660    GLDrawFunctor(WebView* _wvInstance,
661            bool(WebView::*_funcPtr)(WebCore::IntRect&, WebCore::IntRect*,
662                    WebCore::IntRect&, int, WebCore::IntRect&, jfloat, jint),
663            WebCore::IntRect _viewRect, float _scale, int _extras) {
664        wvInstance = _wvInstance;
665        funcPtr = _funcPtr;
666        viewRect = _viewRect;
667        scale = _scale;
668        extras = _extras;
669    };
670    status_t operator()(int messageId, void* data) {
671        if (viewRect.isEmpty()) {
672            // NOOP operation if viewport is empty
673            return 0;
674        }
675
676        WebCore::IntRect inval;
677        int titlebarHeight = webViewRect.height() - viewRect.height();
678
679        uirenderer::DrawGlInfo* info = reinterpret_cast<uirenderer::DrawGlInfo*>(data);
680        WebCore::IntRect localViewRect = viewRect;
681        if (info->isLayer)
682            localViewRect.move(-1 * localViewRect.x(), -1 * localViewRect.y());
683
684        WebCore::IntRect clip(info->clipLeft, info->clipTop,
685                              info->clipRight - info->clipLeft,
686                              info->clipBottom - info->clipTop);
687        TilesManager::instance()->shader()->setWebViewMatrix(info->transform, info->isLayer);
688
689        bool retVal = (*wvInstance.*funcPtr)(localViewRect, &inval, webViewRect,
690                titlebarHeight, clip, scale, extras);
691        if (retVal) {
692            IntRect finalInval;
693            if (inval.isEmpty()) {
694                finalInval = webViewRect;
695                retVal = true;
696            } else {
697                finalInval.setX(webViewRect.x() + inval.x());
698                finalInval.setY(webViewRect.y() + titlebarHeight + inval.y());
699                finalInval.setWidth(inval.width());
700                finalInval.setHeight(inval.height());
701            }
702            info->dirtyLeft = finalInval.x();
703            info->dirtyTop = finalInval.y();
704            info->dirtyRight = finalInval.maxX();
705            info->dirtyBottom = finalInval.maxY();
706        }
707        // return 1 if invalidation needed, 0 otherwise
708        return retVal ? 1 : 0;
709    }
710    void updateRect(WebCore::IntRect& _viewRect) {
711        viewRect = _viewRect;
712    }
713    void updateViewRect(WebCore::IntRect& _viewRect) {
714        webViewRect = _viewRect;
715    }
716    void updateScale(float _scale) {
717        scale = _scale;
718    }
719    private:
720    WebView* wvInstance;
721    bool (WebView::*funcPtr)(WebCore::IntRect&, WebCore::IntRect*,
722            WebCore::IntRect&, int, WebCore::IntRect&, float, int);
723    WebCore::IntRect viewRect;
724    WebCore::IntRect webViewRect;
725    jfloat scale;
726    jint extras;
727};
728
729/*
730 * Native JNI methods
731 */
732
733static void nativeCreate(JNIEnv *env, jobject obj, int viewImpl,
734                         jstring drawableDir, jboolean isHighEndGfx)
735{
736    WTF::String dir = jstringToWtfString(env, drawableDir);
737    new WebView(env, obj, viewImpl, dir, isHighEndGfx);
738    // NEED THIS OR SOMETHING LIKE IT!
739    //Release(obj);
740}
741
742static WebCore::IntRect jrect_to_webrect(JNIEnv* env, jobject obj)
743{
744    if (obj) {
745        int L, T, R, B;
746        GraphicsJNI::get_jrect(env, obj, &L, &T, &R, &B);
747        return WebCore::IntRect(L, T, R - L, B - T);
748    } else
749        return WebCore::IntRect();
750}
751
752static SkRect jrectf_to_rect(JNIEnv* env, jobject obj)
753{
754    SkRect rect = SkRect::MakeEmpty();
755    if (obj)
756        GraphicsJNI::jrectf_to_rect(env, obj, &rect);
757    return rect;
758}
759
760static jint nativeDraw(JNIEnv *env, jobject obj, jobject canv,
761        jobject visible, jint color,
762        jint extras, jboolean split) {
763    SkCanvas* canvas = GraphicsJNI::getNativeCanvas(env, canv);
764    WebView* webView = GET_NATIVE_VIEW(env, obj);
765    SkRect visibleRect = jrectf_to_rect(env, visible);
766    webView->setVisibleRect(visibleRect);
767    PictureSet* pictureSet = webView->draw(canvas, color,
768            static_cast<WebView::DrawExtras>(extras), split);
769    return reinterpret_cast<jint>(pictureSet);
770}
771
772static jint nativeGetDrawGLFunction(JNIEnv *env, jobject obj, jint nativeView,
773                                    jobject jrect, jobject jviewrect,
774                                    jobject jvisiblerect,
775                                    jfloat scale, jint extras) {
776    WebCore::IntRect viewRect = jrect_to_webrect(env, jrect);
777    WebView *wvInstance = (WebView*) nativeView;
778    SkRect visibleRect = jrectf_to_rect(env, jvisiblerect);
779    wvInstance->setVisibleRect(visibleRect);
780
781    GLDrawFunctor* functor = new GLDrawFunctor(wvInstance,
782            &android::WebView::drawGL, viewRect, scale, extras);
783    wvInstance->setFunctor((Functor*) functor);
784
785    WebCore::IntRect webViewRect = jrect_to_webrect(env, jviewrect);
786    functor->updateViewRect(webViewRect);
787
788    return (jint)functor;
789}
790
791static void nativeUpdateDrawGLFunction(JNIEnv *env, jobject obj, jobject jrect,
792        jobject jviewrect, jobject jvisiblerect, jfloat scale) {
793    WebView *wvInstance = GET_NATIVE_VIEW(env, obj);
794    if (wvInstance) {
795        GLDrawFunctor* functor = (GLDrawFunctor*) wvInstance->getFunctor();
796        if (functor) {
797            WebCore::IntRect viewRect = jrect_to_webrect(env, jrect);
798            functor->updateRect(viewRect);
799
800            SkRect visibleRect = jrectf_to_rect(env, jvisiblerect);
801            wvInstance->setVisibleRect(visibleRect);
802
803            WebCore::IntRect webViewRect = jrect_to_webrect(env, jviewrect);
804            functor->updateViewRect(webViewRect);
805
806            functor->updateScale(scale);
807        }
808    }
809}
810
811static bool nativeEvaluateLayersAnimations(JNIEnv *env, jobject obj, jint nativeView)
812{
813    // only call in software rendering, initialize and evaluate animations
814#if USE(ACCELERATED_COMPOSITING)
815    LayerAndroid* root = ((WebView*)nativeView)->compositeRoot();
816    if (root) {
817        root->initAnimations();
818        return root->evaluateAnimations();
819    }
820#endif
821    return false;
822}
823
824static bool nativeSetBaseLayer(JNIEnv *env, jobject obj, jint nativeView, jint layer, jobject inval,
825                               jboolean showVisualIndicator,
826                               jboolean isPictureAfterFirstLayout)
827{
828    BaseLayerAndroid* layerImpl = reinterpret_cast<BaseLayerAndroid*>(layer);
829    SkRegion invalRegion;
830    if (inval)
831        invalRegion = *GraphicsJNI::getNativeRegion(env, inval);
832    return ((WebView*)nativeView)->setBaseLayer(layerImpl, invalRegion, showVisualIndicator,
833                                                isPictureAfterFirstLayout);
834}
835
836static BaseLayerAndroid* nativeGetBaseLayer(JNIEnv *env, jobject obj)
837{
838    return GET_NATIVE_VIEW(env, obj)->getBaseLayer();
839}
840
841static void nativeReplaceBaseContent(JNIEnv *env, jobject obj, jint content)
842{
843    PictureSet* set = reinterpret_cast<PictureSet*>(content);
844    GET_NATIVE_VIEW(env, obj)->replaceBaseContent(set);
845}
846
847static void nativeCopyBaseContentToPicture(JNIEnv *env, jobject obj, jobject pict)
848{
849    SkPicture* picture = GraphicsJNI::getNativePicture(env, pict);
850    GET_NATIVE_VIEW(env, obj)->copyBaseContentToPicture(picture);
851}
852
853static bool nativeHasContent(JNIEnv *env, jobject obj)
854{
855    return GET_NATIVE_VIEW(env, obj)->hasContent();
856}
857
858static jobject nativeLayerBounds(JNIEnv* env, jobject obj, jint jlayer)
859{
860    SkRect r;
861#if USE(ACCELERATED_COMPOSITING)
862    LayerAndroid* layer = (LayerAndroid*) jlayer;
863    r = layer->bounds();
864#else
865    r.setEmpty();
866#endif
867    SkIRect irect;
868    r.round(&irect);
869    jclass rectClass = env->FindClass("android/graphics/Rect");
870    jmethodID init = env->GetMethodID(rectClass, "<init>", "(IIII)V");
871    jobject rect = env->NewObject(rectClass, init, irect.fLeft, irect.fTop,
872        irect.fRight, irect.fBottom);
873    env->DeleteLocalRef(rectClass);
874    return rect;
875}
876
877static void nativeSetHeightCanMeasure(JNIEnv *env, jobject obj, bool measure)
878{
879    WebView* view = GET_NATIVE_VIEW(env, obj);
880    ALOG_ASSERT(view, "view not set in nativeSetHeightCanMeasure");
881    view->setHeightCanMeasure(measure);
882}
883
884static void nativeDestroy(JNIEnv *env, jobject obj)
885{
886    WebView* view = GET_NATIVE_VIEW(env, obj);
887    ALOGD("nativeDestroy view: %p", view);
888    ALOG_ASSERT(view, "view not set in nativeDestroy");
889    delete view;
890}
891
892static void nativeStopGL(JNIEnv *env, jobject obj)
893{
894    GET_NATIVE_VIEW(env, obj)->stopGL();
895}
896
897static jobject nativeGetSelection(JNIEnv *env, jobject obj)
898{
899    WebView* view = GET_NATIVE_VIEW(env, obj);
900    ALOG_ASSERT(view, "view not set in %s", __FUNCTION__);
901    String selection = view->getSelection();
902    return wtfStringToJstring(env, selection);
903}
904
905static void nativeDiscardAllTextures(JNIEnv *env, jobject obj)
906{
907    //discard all textures for debugging/test purposes, but not gl backing memory
908    bool allTextures = true, deleteGLTextures = false;
909    TilesManager::instance()->discardTextures(allTextures, deleteGLTextures);
910}
911
912static void nativeTileProfilingStart(JNIEnv *env, jobject obj)
913{
914    TilesManager::instance()->getProfiler()->start();
915}
916
917static float nativeTileProfilingStop(JNIEnv *env, jobject obj)
918{
919    return TilesManager::instance()->getProfiler()->stop();
920}
921
922static void nativeTileProfilingClear(JNIEnv *env, jobject obj)
923{
924    TilesManager::instance()->getProfiler()->clear();
925}
926
927static int nativeTileProfilingNumFrames(JNIEnv *env, jobject obj)
928{
929    return TilesManager::instance()->getProfiler()->numFrames();
930}
931
932static int nativeTileProfilingNumTilesInFrame(JNIEnv *env, jobject obj, int frame)
933{
934    return TilesManager::instance()->getProfiler()->numTilesInFrame(frame);
935}
936
937static int nativeTileProfilingGetInt(JNIEnv *env, jobject obj, int frame, int tile, jstring jkey)
938{
939    WTF::String key = jstringToWtfString(env, jkey);
940    TileProfileRecord* record = TilesManager::instance()->getProfiler()->getTile(frame, tile);
941
942    if (key == "left")
943        return record->left;
944    if (key == "top")
945        return record->top;
946    if (key == "right")
947        return record->right;
948    if (key == "bottom")
949        return record->bottom;
950    if (key == "level")
951        return record->level;
952    if (key == "isReady")
953        return record->isReady ? 1 : 0;
954    return -1;
955}
956
957static float nativeTileProfilingGetFloat(JNIEnv *env, jobject obj, int frame, int tile, jstring jkey)
958{
959    TileProfileRecord* record = TilesManager::instance()->getProfiler()->getTile(frame, tile);
960    return record->scale;
961}
962
963#ifdef ANDROID_DUMP_DISPLAY_TREE
964static void dumpToFile(const char text[], void* file) {
965    fwrite(text, 1, strlen(text), reinterpret_cast<FILE*>(file));
966    fwrite("\n", 1, 1, reinterpret_cast<FILE*>(file));
967}
968#endif
969
970static bool nativeSetProperty(JNIEnv *env, jobject obj, jstring jkey, jstring jvalue)
971{
972    WTF::String key = jstringToWtfString(env, jkey);
973    WTF::String value = jstringToWtfString(env, jvalue);
974    if (key == "inverted") {
975        bool shouldInvert = (value == "true");
976        TilesManager::instance()->setInvertedScreen(shouldInvert);
977        return true;
978    }
979    else if (key == "inverted_contrast") {
980        float contrast = value.toFloat();
981        TilesManager::instance()->setInvertedScreenContrast(contrast);
982        return true;
983    }
984    else if (key == "enable_cpu_upload_path") {
985        TilesManager::instance()->transferQueue()->setTextureUploadType(
986            value == "true" ? CpuUpload : GpuUpload);
987        return true;
988    }
989    else if (key == "use_minimal_memory") {
990        TilesManager::instance()->setUseMinimalMemory(value == "true");
991        return true;
992    }
993    else if (key == "use_double_buffering") {
994        TilesManager::instance()->setUseDoubleBuffering(value == "true");
995        return true;
996    }
997    else if (key == "tree_updates") {
998        TilesManager::instance()->clearContentUpdates();
999        return true;
1000    }
1001    return false;
1002}
1003
1004static jstring nativeGetProperty(JNIEnv *env, jobject obj, jstring jkey)
1005{
1006    WTF::String key = jstringToWtfString(env, jkey);
1007    if (key == "tree_updates") {
1008        int updates = TilesManager::instance()->getContentUpdates();
1009        WTF::String wtfUpdates = WTF::String::number(updates);
1010        return wtfStringToJstring(env, wtfUpdates);
1011    }
1012    return 0;
1013}
1014
1015static void nativeOnTrimMemory(JNIEnv *env, jobject obj, jint level)
1016{
1017    if (TilesManager::hardwareAccelerationEnabled()) {
1018        // When we got TRIM_MEMORY_MODERATE or TRIM_MEMORY_COMPLETE, we should
1019        // make sure the transfer queue is empty and then abandon the Surface
1020        // Texture to avoid ANR b/c framework may destroy the EGL context.
1021        // Refer to WindowManagerImpl.java for conditions we followed.
1022        TilesManager* tilesManager = TilesManager::instance();
1023        if (level >= TRIM_MEMORY_MODERATE
1024            && !tilesManager->highEndGfx()) {
1025            ALOGD("OnTrimMemory with EGL Context %p", eglGetCurrentContext());
1026            tilesManager->transferQueue()->emptyQueue();
1027            tilesManager->shader()->cleanupGLResources();
1028            tilesManager->videoLayerManager()->cleanupGLResources();
1029        }
1030
1031        bool freeAllTextures = (level > TRIM_MEMORY_UI_HIDDEN), glTextures = true;
1032        tilesManager->discardTextures(freeAllTextures, glTextures);
1033    }
1034}
1035
1036static void nativeDumpDisplayTree(JNIEnv* env, jobject jwebview, jstring jurl)
1037{
1038#ifdef ANDROID_DUMP_DISPLAY_TREE
1039    WebView* view = GET_NATIVE_VIEW(env, jwebview);
1040    ALOG_ASSERT(view, "view not set in %s", __FUNCTION__);
1041
1042    if (view && view->getWebViewCore()) {
1043        FILE* file = fopen(DISPLAY_TREE_LOG_FILE, "w");
1044        if (file) {
1045            SkFormatDumper dumper(dumpToFile, file);
1046            // dump the URL
1047            if (jurl) {
1048                const char* str = env->GetStringUTFChars(jurl, 0);
1049                SkDebugf("Dumping %s to %s\n", str, DISPLAY_TREE_LOG_FILE);
1050                dumpToFile(str, file);
1051                env->ReleaseStringUTFChars(jurl, str);
1052            }
1053            // now dump the display tree
1054            SkDumpCanvas canvas(&dumper);
1055            // this will playback the picture into the canvas, which will
1056            // spew its contents to the dumper
1057            view->draw(&canvas, 0, WebView::DrawExtrasNone, false);
1058            // we're done with the file now
1059            fwrite("\n", 1, 1, file);
1060            fclose(file);
1061        }
1062#if USE(ACCELERATED_COMPOSITING)
1063        const LayerAndroid* rootLayer = view->compositeRoot();
1064        if (rootLayer) {
1065          FILE* file = fopen(LAYERS_TREE_LOG_FILE,"w");
1066          if (file) {
1067              rootLayer->dumpLayers(file, 0);
1068              fclose(file);
1069          }
1070        }
1071#endif
1072    }
1073#endif
1074}
1075
1076static int nativeScrollableLayer(JNIEnv* env, jobject jwebview, jint x, jint y,
1077    jobject rect, jobject bounds)
1078{
1079    WebView* view = GET_NATIVE_VIEW(env, jwebview);
1080    ALOG_ASSERT(view, "view not set in %s", __FUNCTION__);
1081    SkIRect nativeRect, nativeBounds;
1082    int id = view->scrollableLayer(x, y, &nativeRect, &nativeBounds);
1083    if (rect)
1084        GraphicsJNI::irect_to_jrect(nativeRect, env, rect);
1085    if (bounds)
1086        GraphicsJNI::irect_to_jrect(nativeBounds, env, bounds);
1087    return id;
1088}
1089
1090static bool nativeScrollLayer(JNIEnv* env, jobject obj, jint layerId, jint x,
1091        jint y)
1092{
1093#if ENABLE(ANDROID_OVERFLOW_SCROLL)
1094    WebView* view = GET_NATIVE_VIEW(env, obj);
1095    view->scrollLayer(layerId, x, y);
1096
1097    //TODO: the below only needed for the SW rendering path
1098    LayerAndroid* root = view->compositeRoot();
1099    if (!root)
1100        return false;
1101    LayerAndroid* layer = root->findById(layerId);
1102    if (!layer || !layer->contentIsScrollable())
1103        return false;
1104    return static_cast<ScrollableLayerAndroid*>(layer)->scrollTo(x, y);
1105#endif
1106    return false;
1107}
1108
1109static void nativeSetIsScrolling(JNIEnv* env, jobject jwebview, jboolean isScrolling)
1110{
1111    WebView* view = GET_NATIVE_VIEW(env, jwebview);
1112    ALOG_ASSERT(view, "view not set in %s", __FUNCTION__);
1113    view->setIsScrolling(isScrolling);
1114}
1115
1116static void nativeUseHardwareAccelSkia(JNIEnv*, jobject, jboolean enabled)
1117{
1118    BaseRenderer::setCurrentRendererType(enabled ? BaseRenderer::Ganesh : BaseRenderer::Raster);
1119}
1120
1121static int nativeGetBackgroundColor(JNIEnv* env, jobject obj)
1122{
1123    WebView* view = GET_NATIVE_VIEW(env, obj);
1124    BaseLayerAndroid* baseLayer = view->getBaseLayer();
1125    if (baseLayer) {
1126        WebCore::Color color = baseLayer->getBackgroundColor();
1127        if (color.isValid())
1128            return SkColorSetARGB(color.alpha(), color.red(),
1129                                  color.green(), color.blue());
1130    }
1131    return SK_ColorWHITE;
1132}
1133
1134static void nativeSetPauseDrawing(JNIEnv *env, jobject obj, jint nativeView,
1135                                      jboolean pause)
1136{
1137    ((WebView*)nativeView)->m_isDrawingPaused = pause;
1138}
1139
1140static void nativeSetTextSelection(JNIEnv *env, jobject obj, jint nativeView,
1141                                   jint selectionPtr)
1142{
1143    SelectText* selection = reinterpret_cast<SelectText*>(selectionPtr);
1144    reinterpret_cast<WebView*>(nativeView)->setTextSelection(selection);
1145}
1146
1147static jint nativeGetHandleLayerId(JNIEnv *env, jobject obj, jint nativeView,
1148                                     jint handleIndex, jobject cursorRect)
1149{
1150    WebView* webview = reinterpret_cast<WebView*>(nativeView);
1151    SkIRect nativeRect;
1152    int layerId = webview->getHandleLayerId((SelectText::HandleId) handleIndex, nativeRect);
1153    if (cursorRect)
1154        GraphicsJNI::irect_to_jrect(nativeRect, env, cursorRect);
1155    return layerId;
1156}
1157
1158static jboolean nativeIsBaseFirst(JNIEnv *env, jobject obj, jint nativeView)
1159{
1160    WebView* webview = reinterpret_cast<WebView*>(nativeView);
1161    SelectText* select = static_cast<SelectText*>(
1162            webview->getDrawExtra(WebView::DrawExtrasSelection));
1163    return select ? select->isBaseFirst() : false;
1164}
1165
1166/*
1167 * JNI registration
1168 */
1169static JNINativeMethod gJavaWebViewMethods[] = {
1170    { "nativeCreate", "(ILjava/lang/String;Z)V",
1171        (void*) nativeCreate },
1172    { "nativeDestroy", "()V",
1173        (void*) nativeDestroy },
1174    { "nativeDraw", "(Landroid/graphics/Canvas;Landroid/graphics/RectF;IIZ)I",
1175        (void*) nativeDraw },
1176    { "nativeGetDrawGLFunction", "(ILandroid/graphics/Rect;Landroid/graphics/Rect;Landroid/graphics/RectF;FI)I",
1177        (void*) nativeGetDrawGLFunction },
1178    { "nativeUpdateDrawGLFunction", "(Landroid/graphics/Rect;Landroid/graphics/Rect;Landroid/graphics/RectF;F)V",
1179        (void*) nativeUpdateDrawGLFunction },
1180    { "nativeDumpDisplayTree", "(Ljava/lang/String;)V",
1181        (void*) nativeDumpDisplayTree },
1182    { "nativeEvaluateLayersAnimations", "(I)Z",
1183        (void*) nativeEvaluateLayersAnimations },
1184    { "nativeGetSelection", "()Ljava/lang/String;",
1185        (void*) nativeGetSelection },
1186    { "nativeLayerBounds", "(I)Landroid/graphics/Rect;",
1187        (void*) nativeLayerBounds },
1188    { "nativeSetHeightCanMeasure", "(Z)V",
1189        (void*) nativeSetHeightCanMeasure },
1190    { "nativeSetBaseLayer", "(IILandroid/graphics/Region;ZZ)Z",
1191        (void*) nativeSetBaseLayer },
1192    { "nativeGetBaseLayer", "()I",
1193        (void*) nativeGetBaseLayer },
1194    { "nativeReplaceBaseContent", "(I)V",
1195        (void*) nativeReplaceBaseContent },
1196    { "nativeCopyBaseContentToPicture", "(Landroid/graphics/Picture;)V",
1197        (void*) nativeCopyBaseContentToPicture },
1198    { "nativeHasContent", "()Z",
1199        (void*) nativeHasContent },
1200    { "nativeDiscardAllTextures", "()V",
1201        (void*) nativeDiscardAllTextures },
1202    { "nativeTileProfilingStart", "()V",
1203        (void*) nativeTileProfilingStart },
1204    { "nativeTileProfilingStop", "()F",
1205        (void*) nativeTileProfilingStop },
1206    { "nativeTileProfilingClear", "()V",
1207        (void*) nativeTileProfilingClear },
1208    { "nativeTileProfilingNumFrames", "()I",
1209        (void*) nativeTileProfilingNumFrames },
1210    { "nativeTileProfilingNumTilesInFrame", "(I)I",
1211        (void*) nativeTileProfilingNumTilesInFrame },
1212    { "nativeTileProfilingGetInt", "(IILjava/lang/String;)I",
1213        (void*) nativeTileProfilingGetInt },
1214    { "nativeTileProfilingGetFloat", "(IILjava/lang/String;)F",
1215        (void*) nativeTileProfilingGetFloat },
1216    { "nativeStopGL", "()V",
1217        (void*) nativeStopGL },
1218    { "nativeScrollableLayer", "(IILandroid/graphics/Rect;Landroid/graphics/Rect;)I",
1219        (void*) nativeScrollableLayer },
1220    { "nativeScrollLayer", "(III)Z",
1221        (void*) nativeScrollLayer },
1222    { "nativeSetIsScrolling", "(Z)V",
1223        (void*) nativeSetIsScrolling },
1224    { "nativeUseHardwareAccelSkia", "(Z)V",
1225        (void*) nativeUseHardwareAccelSkia },
1226    { "nativeGetBackgroundColor", "()I",
1227        (void*) nativeGetBackgroundColor },
1228    { "nativeSetProperty", "(Ljava/lang/String;Ljava/lang/String;)Z",
1229        (void*) nativeSetProperty },
1230    { "nativeGetProperty", "(Ljava/lang/String;)Ljava/lang/String;",
1231        (void*) nativeGetProperty },
1232    { "nativeOnTrimMemory", "(I)V",
1233        (void*) nativeOnTrimMemory },
1234    { "nativeSetPauseDrawing", "(IZ)V",
1235        (void*) nativeSetPauseDrawing },
1236    { "nativeSetTextSelection", "(II)V",
1237        (void*) nativeSetTextSelection },
1238    { "nativeGetHandleLayerId", "(IILandroid/graphics/Rect;)I",
1239        (void*) nativeGetHandleLayerId },
1240    { "nativeIsBaseFirst", "(I)Z",
1241        (void*) nativeIsBaseFirst },
1242};
1243
1244int registerWebView(JNIEnv* env)
1245{
1246    jclass clazz = env->FindClass("android/webkit/WebViewClassic");
1247    ALOG_ASSERT(clazz, "Unable to find class android/webkit/WebViewClassic");
1248    gWebViewField = env->GetFieldID(clazz, "mNativeClass", "I");
1249    ALOG_ASSERT(gWebViewField, "Unable to find android/webkit/WebViewClassic.mNativeClass");
1250    env->DeleteLocalRef(clazz);
1251
1252    return jniRegisterNativeMethods(env, "android/webkit/WebViewClassic", gJavaWebViewMethods, NELEM(gJavaWebViewMethods));
1253}
1254
1255} // namespace android
1256