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