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