WebView.cpp revision 57ae1393d3097edada2640b40c895396b69cc919
1/*
2 * Copyright 2007, The Android Open Source Project
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 *  * Redistributions of source code must retain the above copyright
8 *    notice, this list of conditions and the following disclaimer.
9 *  * Redistributions in binary form must reproduce the above copyright
10 *    notice, this list of conditions and the following disclaimer in the
11 *    documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#define LOG_TAG "webviewglue"
27
28#include "config.h"
29
30#include "AndroidAnimation.h"
31#include "AndroidLog.h"
32#include "BaseLayerAndroid.h"
33#include "DrawExtra.h"
34#include "Frame.h"
35#include "GraphicsJNI.h"
36#include "HTMLInputElement.h"
37#include "IntPoint.h"
38#include "IntRect.h"
39#include "LayerAndroid.h"
40#include "Node.h"
41#include "utils/Functor.h"
42#include "private/hwui/DrawGlInfo.h"
43#include "PlatformGraphicsContext.h"
44#include "PlatformString.h"
45#include "ScrollableLayerAndroid.h"
46#include "SelectText.h"
47#include "SkCanvas.h"
48#include "SkDumpCanvas.h"
49#include "SkPicture.h"
50#include "SkRect.h"
51#include "SkTime.h"
52#include "TilesManager.h"
53#include "WebCoreJni.h"
54#include "WebRequestContext.h"
55#include "WebViewCore.h"
56#include "android_graphics.h"
57
58#ifdef GET_NATIVE_VIEW
59#undef GET_NATIVE_VIEW
60#endif
61
62#define GET_NATIVE_VIEW(env, obj) ((WebView*)env->GetIntField(obj, gWebViewField))
63
64#include <JNIUtility.h>
65#include <JNIHelp.h>
66#include <jni.h>
67#include <androidfw/KeycodeLabels.h>
68#include <wtf/text/AtomicString.h>
69#include <wtf/text/CString.h>
70
71// Free as much as we possible can
72#define TRIM_MEMORY_COMPLETE 80
73// Free a lot (all textures gone)
74#define TRIM_MEMORY_MODERATE 60
75// More moderate free (keep bare minimum to restore quickly-ish - possibly clear all textures)
76#define TRIM_MEMORY_BACKGROUND 40
77// Moderate free (clear cached tiles, keep visible ones)
78#define TRIM_MEMORY_UI_HIDDEN 20
79// Duration to show the pressed cursor ring
80#define PRESSED_STATE_DURATION 400
81
82namespace android {
83
84static jfieldID gWebViewField;
85
86//-------------------------------------
87
88static jmethodID GetJMethod(JNIEnv* env, jclass clazz, const char name[], const char signature[])
89{
90    jmethodID m = env->GetMethodID(clazz, name, signature);
91    ALOG_ASSERT(m, "Could not find method %s", name);
92    return m;
93}
94
95//-------------------------------------
96// This class provides JNI for making calls into native code from the UI side
97// of the multi-threaded WebView.
98class WebView
99{
100public:
101enum FrameCachePermission {
102    DontAllowNewer,
103    AllowNewer
104};
105
106#define DRAW_EXTRAS_SIZE 2
107enum DrawExtras { // keep this in sync with WebView.java
108    DrawExtrasNone = 0,
109    DrawExtrasSelection = 1,
110    DrawExtrasCursorRing = 2
111};
112
113struct JavaGlue {
114    jweak       m_obj;
115    jmethodID   m_overrideLoading;
116    jmethodID   m_scrollBy;
117    jmethodID   m_sendMoveFocus;
118    jmethodID   m_sendMoveMouse;
119    jmethodID   m_sendMoveMouseIfLatest;
120    jmethodID   m_sendMotionUp;
121    jmethodID   m_domChangedFocus;
122    jmethodID   m_getScaledMaxXScroll;
123    jmethodID   m_getScaledMaxYScroll;
124    jmethodID   m_getVisibleRect;
125    jmethodID   m_rebuildWebTextView;
126    jmethodID   m_viewInvalidate;
127    jmethodID   m_viewInvalidateRect;
128    jmethodID   m_postInvalidateDelayed;
129    jmethodID   m_pageSwapCallback;
130    jfieldID    m_rectLeft;
131    jfieldID    m_rectTop;
132    jmethodID   m_rectWidth;
133    jmethodID   m_rectHeight;
134    jfieldID    m_rectFLeft;
135    jfieldID    m_rectFTop;
136    jmethodID   m_rectFWidth;
137    jmethodID   m_rectFHeight;
138    AutoJObject object(JNIEnv* env) {
139        return getRealObject(env, m_obj);
140    }
141} m_javaGlue;
142
143WebView(JNIEnv* env, jobject javaWebView, int viewImpl, WTF::String drawableDir,
144        bool isHighEndGfx)
145    : m_isHighEndGfx(isHighEndGfx)
146{
147    memset(m_extras, 0, DRAW_EXTRAS_SIZE * sizeof(DrawExtra*));
148    jclass clazz = env->FindClass("android/webkit/WebViewClassic");
149 //   m_javaGlue = new JavaGlue;
150    m_javaGlue.m_obj = env->NewWeakGlobalRef(javaWebView);
151    m_javaGlue.m_scrollBy = GetJMethod(env, clazz, "setContentScrollBy", "(IIZ)Z");
152    m_javaGlue.m_overrideLoading = GetJMethod(env, clazz, "overrideLoading", "(Ljava/lang/String;)V");
153    m_javaGlue.m_sendMoveFocus = GetJMethod(env, clazz, "sendMoveFocus", "(II)V");
154    m_javaGlue.m_sendMoveMouse = GetJMethod(env, clazz, "sendMoveMouse", "(IIII)V");
155    m_javaGlue.m_sendMoveMouseIfLatest = GetJMethod(env, clazz, "sendMoveMouseIfLatest", "(ZZ)V");
156    m_javaGlue.m_sendMotionUp = GetJMethod(env, clazz, "sendMotionUp", "(IIIII)V");
157    m_javaGlue.m_domChangedFocus = GetJMethod(env, clazz, "domChangedFocus", "()V");
158    m_javaGlue.m_getScaledMaxXScroll = GetJMethod(env, clazz, "getScaledMaxXScroll", "()I");
159    m_javaGlue.m_getScaledMaxYScroll = GetJMethod(env, clazz, "getScaledMaxYScroll", "()I");
160    m_javaGlue.m_getVisibleRect = GetJMethod(env, clazz, "sendOurVisibleRect", "()Landroid/graphics/Rect;");
161    m_javaGlue.m_rebuildWebTextView = GetJMethod(env, clazz, "rebuildWebTextView", "()V");
162    m_javaGlue.m_viewInvalidate = GetJMethod(env, clazz, "viewInvalidate", "()V");
163    m_javaGlue.m_viewInvalidateRect = GetJMethod(env, clazz, "viewInvalidate", "(IIII)V");
164    m_javaGlue.m_postInvalidateDelayed = GetJMethod(env, clazz,
165        "viewInvalidateDelayed", "(JIIII)V");
166    m_javaGlue.m_pageSwapCallback = GetJMethod(env, clazz, "pageSwapCallback", "(Z)V");
167    env->DeleteLocalRef(clazz);
168
169    jclass rectClass = env->FindClass("android/graphics/Rect");
170    ALOG_ASSERT(rectClass, "Could not find Rect class");
171    m_javaGlue.m_rectLeft = env->GetFieldID(rectClass, "left", "I");
172    m_javaGlue.m_rectTop = env->GetFieldID(rectClass, "top", "I");
173    m_javaGlue.m_rectWidth = GetJMethod(env, rectClass, "width", "()I");
174    m_javaGlue.m_rectHeight = GetJMethod(env, rectClass, "height", "()I");
175    env->DeleteLocalRef(rectClass);
176
177    jclass rectClassF = env->FindClass("android/graphics/RectF");
178    ALOG_ASSERT(rectClassF, "Could not find RectF class");
179    m_javaGlue.m_rectFLeft = env->GetFieldID(rectClassF, "left", "F");
180    m_javaGlue.m_rectFTop = env->GetFieldID(rectClassF, "top", "F");
181    m_javaGlue.m_rectFWidth = GetJMethod(env, rectClassF, "width", "()F");
182    m_javaGlue.m_rectFHeight = GetJMethod(env, rectClassF, "height", "()F");
183    env->DeleteLocalRef(rectClassF);
184
185    env->SetIntField(javaWebView, gWebViewField, (jint)this);
186    m_viewImpl = (WebViewCore*) viewImpl;
187    m_generation = 0;
188    m_heightCanMeasure = false;
189    m_lastDx = 0;
190    m_lastDxTime = 0;
191    m_baseLayer = 0;
192    m_glDrawFunctor = 0;
193    m_isDrawingPaused = false;
194#if USE(ACCELERATED_COMPOSITING)
195    m_glWebViewState = 0;
196#endif
197}
198
199~WebView()
200{
201    if (m_javaGlue.m_obj)
202    {
203        JNIEnv* env = JSC::Bindings::getJNIEnv();
204        env->DeleteWeakGlobalRef(m_javaGlue.m_obj);
205        m_javaGlue.m_obj = 0;
206    }
207#if USE(ACCELERATED_COMPOSITING)
208    // We must remove the m_glWebViewState prior to deleting m_baseLayer. If we
209    // do not remove it here, we risk having BaseTiles trying to paint using a
210    // deallocated base layer.
211    stopGL();
212#endif
213    SkSafeUnref(m_baseLayer);
214    delete m_glDrawFunctor;
215    for (int i = 0; i < DRAW_EXTRAS_SIZE; i++)
216        delete m_extras[i];
217}
218
219DrawExtra* getDrawExtra(DrawExtras extras)
220{
221    if (extras == DrawExtrasNone)
222        return 0;
223    return m_extras[extras - 1];
224}
225
226void stopGL()
227{
228#if USE(ACCELERATED_COMPOSITING)
229    delete m_glWebViewState;
230    m_glWebViewState = 0;
231#endif
232}
233
234WebViewCore* getWebViewCore() const {
235    return m_viewImpl;
236}
237
238void scrollRectOnScreen(const IntRect& rect)
239{
240    if (rect.isEmpty())
241        return;
242    int dx = 0;
243    int left = rect.x();
244    int right = rect.maxX();
245    if (left < m_visibleRect.fLeft)
246        dx = left - m_visibleRect.fLeft;
247    // Only scroll right if the entire width can fit on screen.
248    else if (right > m_visibleRect.fRight
249            && right - left < m_visibleRect.width())
250        dx = right - m_visibleRect.fRight;
251    int dy = 0;
252    int top = rect.y();
253    int bottom = rect.maxY();
254    if (top < m_visibleRect.fTop)
255        dy = top - m_visibleRect.fTop;
256    // Only scroll down if the entire height can fit on screen
257    else if (bottom > m_visibleRect.fBottom
258            && bottom - top < m_visibleRect.height())
259        dy = bottom - m_visibleRect.fBottom;
260    if ((dx|dy) == 0 || !scrollBy(dx, dy))
261        return;
262    viewInvalidate();
263}
264
265bool drawGL(WebCore::IntRect& viewRect, WebCore::IntRect* invalRect,
266        WebCore::IntRect& webViewRect, int titleBarHeight,
267        WebCore::IntRect& clip, float scale, int extras)
268{
269#if USE(ACCELERATED_COMPOSITING)
270    if (!m_baseLayer)
271        return false;
272
273    if (!m_glWebViewState) {
274        TilesManager::instance()->setHighEndGfx(m_isHighEndGfx);
275        m_glWebViewState = new GLWebViewState();
276        if (m_baseLayer->content()) {
277            SkRegion region;
278            SkIRect rect;
279            rect.set(0, 0, m_baseLayer->content()->width(), m_baseLayer->content()->height());
280            region.setRect(rect);
281            m_baseLayer->markAsDirty(region);
282            m_glWebViewState->setBaseLayer(m_baseLayer, false, true);
283        }
284    }
285
286    DrawExtra* extra = getDrawExtra((DrawExtras) extras);
287
288    unsigned int pic = m_glWebViewState->currentPictureCounter();
289    m_glWebViewState->glExtras()->setDrawExtra(extra);
290
291    // Make sure we have valid coordinates. We might not have valid coords
292    // if the zoom manager is still initializing. We will be redrawn
293    // once the correct scale is set
294    if (!m_visibleRect.isFinite())
295        return false;
296    bool treesSwapped = false;
297    bool newTreeHasAnim = false;
298    bool ret = m_glWebViewState->drawGL(viewRect, m_visibleRect, invalRect,
299                                        webViewRect, titleBarHeight, clip, scale,
300                                        &treesSwapped, &newTreeHasAnim);
301    if (treesSwapped) {
302        ALOG_ASSERT(m_javaGlue.m_obj, "A java object was not associated with this native WebView!");
303        JNIEnv* env = JSC::Bindings::getJNIEnv();
304        AutoJObject javaObject = m_javaGlue.object(env);
305        if (javaObject.get()) {
306            env->CallVoidMethod(javaObject.get(), m_javaGlue.m_pageSwapCallback, newTreeHasAnim);
307            checkException(env);
308        }
309    }
310    if (ret || m_glWebViewState->currentPictureCounter() != pic)
311        return !m_isDrawingPaused;
312#endif
313    return false;
314}
315
316PictureSet* draw(SkCanvas* canvas, SkColor bgColor, DrawExtras extras, bool split)
317{
318    PictureSet* ret = 0;
319    if (!m_baseLayer) {
320        canvas->drawColor(bgColor);
321        return ret;
322    }
323
324    // draw the content of the base layer first
325    PictureSet* content = m_baseLayer->content();
326    int sc = canvas->save(SkCanvas::kClip_SaveFlag);
327    canvas->clipRect(SkRect::MakeLTRB(0, 0, content->width(),
328                content->height()), SkRegion::kDifference_Op);
329    canvas->drawColor(bgColor);
330    canvas->restoreToCount(sc);
331    if (content->draw(canvas))
332        ret = split ? new PictureSet(*content) : 0;
333
334    DrawExtra* extra = getDrawExtra(extras);
335    if (extra)
336        extra->draw(canvas, 0);
337
338#if USE(ACCELERATED_COMPOSITING)
339    LayerAndroid* compositeLayer = compositeRoot();
340    if (compositeLayer) {
341        // call this to be sure we've adjusted for any scrolling or animations
342        // before we actually draw
343        compositeLayer->updateFixedLayersPositions(m_visibleRect);
344        compositeLayer->updatePositions();
345        // We have to set the canvas' matrix on the base layer
346        // (to have fixed layers work as intended)
347        SkAutoCanvasRestore restore(canvas, true);
348        m_baseLayer->setMatrix(canvas->getTotalMatrix());
349        canvas->resetMatrix();
350        m_baseLayer->draw(canvas, extra);
351    }
352    if (extra) {
353        IntRect dummy; // inval area, unused for now
354        extra->drawLegacy(canvas, compositeLayer, &dummy);
355    }
356#endif
357    return ret;
358}
359
360int getScaledMaxXScroll()
361{
362    ALOG_ASSERT(m_javaGlue.m_obj, "A java object was not associated with this native WebView!");
363    JNIEnv* env = JSC::Bindings::getJNIEnv();
364    AutoJObject javaObject = m_javaGlue.object(env);
365    if (!javaObject.get())
366        return 0;
367    int result = env->CallIntMethod(javaObject.get(), m_javaGlue.m_getScaledMaxXScroll);
368    checkException(env);
369    return result;
370}
371
372int getScaledMaxYScroll()
373{
374    ALOG_ASSERT(m_javaGlue.m_obj, "A java object was not associated with this native WebView!");
375    JNIEnv* env = JSC::Bindings::getJNIEnv();
376    AutoJObject javaObject = m_javaGlue.object(env);
377    if (!javaObject.get())
378        return 0;
379    int result = env->CallIntMethod(javaObject.get(), m_javaGlue.m_getScaledMaxYScroll);
380    checkException(env);
381    return result;
382}
383
384IntRect getVisibleRect()
385{
386    IntRect rect;
387    ALOG_ASSERT(m_javaGlue.m_obj, "A java object was not associated with this native WebView!");
388    JNIEnv* env = JSC::Bindings::getJNIEnv();
389    AutoJObject javaObject = m_javaGlue.object(env);
390    if (!javaObject.get())
391        return rect;
392    jobject jRect = env->CallObjectMethod(javaObject.get(), m_javaGlue.m_getVisibleRect);
393    checkException(env);
394    rect.setX(env->GetIntField(jRect, m_javaGlue.m_rectLeft));
395    checkException(env);
396    rect.setY(env->GetIntField(jRect, m_javaGlue.m_rectTop));
397    checkException(env);
398    rect.setWidth(env->CallIntMethod(jRect, m_javaGlue.m_rectWidth));
399    checkException(env);
400    rect.setHeight(env->CallIntMethod(jRect, m_javaGlue.m_rectHeight));
401    checkException(env);
402    env->DeleteLocalRef(jRect);
403    checkException(env);
404    return rect;
405}
406
407void notifyProgressFinished()
408{
409    rebuildWebTextView();
410}
411
412#if USE(ACCELERATED_COMPOSITING)
413static const ScrollableLayerAndroid* findScrollableLayer(
414    const LayerAndroid* parent, int x, int y, SkIRect* foundBounds) {
415    SkRect bounds;
416    parent->bounds(&bounds);
417    // Check the parent bounds first; this will clip to within a masking layer's
418    // bounds.
419    if (parent->masksToBounds() && !bounds.contains(x, y))
420        return 0;
421    // Move the hit test local to parent.
422    x -= bounds.fLeft;
423    y -= bounds.fTop;
424    int count = parent->countChildren();
425    while (count--) {
426        const LayerAndroid* child = parent->getChild(count);
427        const ScrollableLayerAndroid* result = findScrollableLayer(child, x, y,
428            foundBounds);
429        if (result) {
430            foundBounds->offset(bounds.fLeft, bounds.fTop);
431            if (parent->masksToBounds()) {
432                if (bounds.width() < foundBounds->width())
433                    foundBounds->fRight = foundBounds->fLeft + bounds.width();
434                if (bounds.height() < foundBounds->height())
435                    foundBounds->fBottom = foundBounds->fTop + bounds.height();
436            }
437            return result;
438        }
439    }
440    if (parent->contentIsScrollable()) {
441        foundBounds->set(0, 0, bounds.width(), bounds.height());
442        return static_cast<const ScrollableLayerAndroid*>(parent);
443    }
444    return 0;
445}
446#endif
447
448int scrollableLayer(int x, int y, SkIRect* layerRect, SkIRect* bounds)
449{
450#if USE(ACCELERATED_COMPOSITING)
451    const LayerAndroid* layerRoot = compositeRoot();
452    if (!layerRoot)
453        return 0;
454    const ScrollableLayerAndroid* result = findScrollableLayer(layerRoot, x, y,
455        bounds);
456    if (result) {
457        result->getScrollRect(layerRect);
458        return result->uniqueId();
459    }
460#endif
461    return 0;
462}
463
464void scrollLayer(int layerId, int x, int y)
465{
466    if (m_glWebViewState)
467        m_glWebViewState->scrollLayer(layerId, x, y);
468}
469
470void overrideUrlLoading(const WTF::String& url)
471{
472    JNIEnv* env = JSC::Bindings::getJNIEnv();
473    AutoJObject javaObject = m_javaGlue.object(env);
474    if (!javaObject.get())
475        return;
476    jstring jName = wtfStringToJstring(env, url);
477    env->CallVoidMethod(javaObject.get(), m_javaGlue.m_overrideLoading, jName);
478    env->DeleteLocalRef(jName);
479}
480
481void setFindIsUp(bool up)
482{
483    m_viewImpl->m_findIsUp = up;
484}
485
486void setHeightCanMeasure(bool measure)
487{
488    m_heightCanMeasure = measure;
489}
490
491String getSelection()
492{
493    SelectText* select = static_cast<SelectText*>(
494            getDrawExtra(WebView::DrawExtrasSelection));
495    if (select)
496        return select->getText();
497    return String();
498}
499
500void sendMoveFocus(WebCore::Frame* framePtr, WebCore::Node* nodePtr)
501{
502    JNIEnv* env = JSC::Bindings::getJNIEnv();
503    AutoJObject javaObject = m_javaGlue.object(env);
504    if (!javaObject.get())
505        return;
506    env->CallVoidMethod(javaObject.get(), m_javaGlue.m_sendMoveFocus, (jint) framePtr, (jint) nodePtr);
507    checkException(env);
508}
509
510void sendMoveMouse(WebCore::Frame* framePtr, WebCore::Node* nodePtr, int x, int y)
511{
512    JNIEnv* env = JSC::Bindings::getJNIEnv();
513    AutoJObject javaObject = m_javaGlue.object(env);
514    if (!javaObject.get())
515        return;
516    env->CallVoidMethod(javaObject.get(), m_javaGlue.m_sendMoveMouse, reinterpret_cast<jint>(framePtr), reinterpret_cast<jint>(nodePtr), x, y);
517    checkException(env);
518}
519
520void sendMoveMouseIfLatest(bool clearTextEntry, bool stopPaintingCaret)
521{
522    ALOG_ASSERT(m_javaGlue.m_obj, "A java object was not associated with this native WebView!");
523    JNIEnv* env = JSC::Bindings::getJNIEnv();
524    AutoJObject javaObject = m_javaGlue.object(env);
525    if (!javaObject.get())
526        return;
527    env->CallVoidMethod(javaObject.get(), m_javaGlue.m_sendMoveMouseIfLatest, clearTextEntry, stopPaintingCaret);
528    checkException(env);
529}
530
531void sendMotionUp(WebCore::Frame* framePtr, WebCore::Node* nodePtr, int x, int y)
532{
533    ALOG_ASSERT(m_javaGlue.m_obj, "A WebView was not associated with this WebViewNative!");
534
535    JNIEnv* env = JSC::Bindings::getJNIEnv();
536    AutoJObject javaObject = m_javaGlue.object(env);
537    if (!javaObject.get())
538        return;
539    m_viewImpl->m_touchGeneration = ++m_generation;
540    env->CallVoidMethod(javaObject.get(), m_javaGlue.m_sendMotionUp, m_generation, (jint) framePtr, (jint) nodePtr, x, y);
541    checkException(env);
542}
543
544bool scrollBy(int dx, int dy)
545{
546    ALOG_ASSERT(m_javaGlue.m_obj, "A java object was not associated with this native WebView!");
547
548    JNIEnv* env = JSC::Bindings::getJNIEnv();
549    AutoJObject javaObject = m_javaGlue.object(env);
550    if (!javaObject.get())
551        return false;
552    bool result = env->CallBooleanMethod(javaObject.get(), m_javaGlue.m_scrollBy, dx, dy, true);
553    checkException(env);
554    return result;
555}
556
557void setIsScrolling(bool isScrolling)
558{
559#if USE(ACCELERATED_COMPOSITING)
560    if (m_glWebViewState)
561        m_glWebViewState->setIsScrolling(isScrolling);
562#endif
563}
564
565void rebuildWebTextView()
566{
567    JNIEnv* env = JSC::Bindings::getJNIEnv();
568    AutoJObject javaObject = m_javaGlue.object(env);
569    if (!javaObject.get())
570        return;
571    env->CallVoidMethod(javaObject.get(), m_javaGlue.m_rebuildWebTextView);
572    checkException(env);
573}
574
575void viewInvalidate()
576{
577    JNIEnv* env = JSC::Bindings::getJNIEnv();
578    AutoJObject javaObject = m_javaGlue.object(env);
579    if (!javaObject.get())
580        return;
581    env->CallVoidMethod(javaObject.get(), m_javaGlue.m_viewInvalidate);
582    checkException(env);
583}
584
585void viewInvalidateRect(int l, int t, int r, int b)
586{
587    JNIEnv* env = JSC::Bindings::getJNIEnv();
588    AutoJObject javaObject = m_javaGlue.object(env);
589    if (!javaObject.get())
590        return;
591    env->CallVoidMethod(javaObject.get(), m_javaGlue.m_viewInvalidateRect, l, r, t, b);
592    checkException(env);
593}
594
595void postInvalidateDelayed(int64_t delay, const WebCore::IntRect& bounds)
596{
597    JNIEnv* env = JSC::Bindings::getJNIEnv();
598    AutoJObject javaObject = m_javaGlue.object(env);
599    if (!javaObject.get())
600        return;
601    env->CallVoidMethod(javaObject.get(), m_javaGlue.m_postInvalidateDelayed,
602        delay, bounds.x(), bounds.y(), bounds.maxX(), bounds.maxY());
603    checkException(env);
604}
605
606int moveGeneration()
607{
608    return m_viewImpl->m_moveGeneration;
609}
610
611LayerAndroid* compositeRoot() const
612{
613    ALOG_ASSERT(!m_baseLayer || m_baseLayer->countChildren() == 1,
614            "base layer can't have more than one child %s", __FUNCTION__);
615    if (m_baseLayer && m_baseLayer->countChildren() == 1)
616        return static_cast<LayerAndroid*>(m_baseLayer->getChild(0));
617    else
618        return 0;
619}
620
621#if ENABLE(ANDROID_OVERFLOW_SCROLL)
622static void copyScrollPositionRecursive(const LayerAndroid* from,
623                                        LayerAndroid* root)
624{
625    if (!from || !root)
626        return;
627    for (int i = 0; i < from->countChildren(); i++) {
628        const LayerAndroid* l = from->getChild(i);
629        if (l->contentIsScrollable()) {
630            const SkPoint& pos = l->getPosition();
631            LayerAndroid* match = root->findById(l->uniqueId());
632            if (match && match->contentIsScrollable())
633                match->setPosition(pos.fX, pos.fY);
634        }
635        copyScrollPositionRecursive(l, root);
636    }
637}
638#endif
639
640bool setBaseLayer(BaseLayerAndroid* layer, SkRegion& inval, bool showVisualIndicator,
641                  bool isPictureAfterFirstLayout)
642{
643    bool queueFull = false;
644#if USE(ACCELERATED_COMPOSITING)
645    if (m_glWebViewState) {
646        if (layer)
647            layer->markAsDirty(inval);
648        queueFull = m_glWebViewState->setBaseLayer(layer, showVisualIndicator,
649                                                   isPictureAfterFirstLayout);
650    }
651#endif
652
653#if ENABLE(ANDROID_OVERFLOW_SCROLL)
654    if (layer) {
655        // TODO: the below tree copies are only necessary in software rendering
656        LayerAndroid* newCompositeRoot = static_cast<LayerAndroid*>(layer->getChild(0));
657        copyScrollPositionRecursive(compositeRoot(), newCompositeRoot);
658    }
659#endif
660    SkSafeUnref(m_baseLayer);
661    m_baseLayer = layer;
662
663    return queueFull;
664}
665
666void replaceBaseContent(PictureSet* set)
667{
668    if (!m_baseLayer)
669        return;
670    m_baseLayer->setContent(*set);
671    delete set;
672}
673
674void copyBaseContentToPicture(SkPicture* picture)
675{
676    if (!m_baseLayer)
677        return;
678    PictureSet* content = m_baseLayer->content();
679    m_baseLayer->drawCanvas(picture->beginRecording(content->width(), content->height(),
680            SkPicture::kUsePathBoundsForClip_RecordingFlag));
681    picture->endRecording();
682}
683
684bool hasContent() {
685    if (!m_baseLayer)
686        return false;
687    return !m_baseLayer->content()->isEmpty();
688}
689
690void setFunctor(Functor* functor) {
691    delete m_glDrawFunctor;
692    m_glDrawFunctor = functor;
693}
694
695Functor* getFunctor() {
696    return m_glDrawFunctor;
697}
698
699BaseLayerAndroid* getBaseLayer() {
700    return m_baseLayer;
701}
702
703void setVisibleRect(SkRect& visibleRect) {
704    m_visibleRect = visibleRect;
705}
706
707void setDrawExtra(DrawExtra *extra, DrawExtras type)
708{
709    if (type == DrawExtrasNone)
710        return;
711    DrawExtra* old = m_extras[type - 1];
712    m_extras[type - 1] = extra;
713    if (old != extra) {
714        delete old;
715    }
716}
717
718void setTextSelection(SelectText *selection) {
719    setDrawExtra(selection, DrawExtrasSelection);
720}
721
722int getHandleLayerId(SelectText::HandleId handleId, SkIRect& cursorRect) {
723    SelectText* selectText = static_cast<SelectText*>(getDrawExtra(DrawExtrasSelection));
724    if (!selectText || !m_baseLayer)
725        return -1;
726    int layerId = selectText->caretLayerId(handleId);
727    IntRect rect = selectText->caretRect(handleId);
728    if (layerId != -1) {
729        // We need to make sure the drawTransform is up to date as this is
730        // called before a draw() or drawGL()
731        m_baseLayer->updateLayerPositions(m_visibleRect);
732        LayerAndroid* root = compositeRoot();
733        LayerAndroid* layer = root ? root->findById(layerId) : 0;
734        if (layer && layer->drawTransform())
735            rect = layer->drawTransform()->mapRect(rect);
736    }
737    cursorRect.set(rect.x(), rect.y(), rect.maxX(), rect.maxY());
738    return layerId;
739}
740
741    bool m_isDrawingPaused;
742private: // local state for WebView
743    // private to getFrameCache(); other functions operate in a different thread
744    WebViewCore* m_viewImpl;
745    int m_generation; // associate unique ID with sent kit focus to match with ui
746    // Corresponds to the same-named boolean on the java side.
747    bool m_heightCanMeasure;
748    int m_lastDx;
749    SkMSec m_lastDxTime;
750    DrawExtra* m_extras[DRAW_EXTRAS_SIZE];
751    BaseLayerAndroid* m_baseLayer;
752    Functor* m_glDrawFunctor;
753#if USE(ACCELERATED_COMPOSITING)
754    GLWebViewState* m_glWebViewState;
755#endif
756    SkRect m_visibleRect;
757    bool m_isHighEndGfx;
758}; // end of WebView class
759
760
761/**
762 * This class holds a function pointer and parameters for calling drawGL into a specific
763 * viewport. The pointer to the Functor will be put on a framework display list to be called
764 * when the display list is replayed.
765 */
766class GLDrawFunctor : Functor {
767    public:
768    GLDrawFunctor(WebView* _wvInstance,
769            bool(WebView::*_funcPtr)(WebCore::IntRect&, WebCore::IntRect*,
770                    WebCore::IntRect&, int, WebCore::IntRect&, jfloat, jint),
771            WebCore::IntRect _viewRect, float _scale, int _extras) {
772        wvInstance = _wvInstance;
773        funcPtr = _funcPtr;
774        viewRect = _viewRect;
775        scale = _scale;
776        extras = _extras;
777    };
778    status_t operator()(int messageId, void* data) {
779        if (viewRect.isEmpty()) {
780            // NOOP operation if viewport is empty
781            return 0;
782        }
783
784        WebCore::IntRect inval;
785        int titlebarHeight = webViewRect.height() - viewRect.height();
786
787        uirenderer::DrawGlInfo* info = reinterpret_cast<uirenderer::DrawGlInfo*>(data);
788        WebCore::IntRect localViewRect = viewRect;
789        if (info->isLayer)
790            localViewRect.move(-1 * localViewRect.x(), -1 * localViewRect.y());
791
792        WebCore::IntRect clip(info->clipLeft, info->clipTop,
793                              info->clipRight - info->clipLeft,
794                              info->clipBottom - info->clipTop);
795        TilesManager::instance()->shader()->setWebViewMatrix(info->transform, info->isLayer);
796
797        bool retVal = (*wvInstance.*funcPtr)(localViewRect, &inval, webViewRect,
798                titlebarHeight, clip, scale, extras);
799        if (retVal) {
800            IntRect finalInval;
801            if (inval.isEmpty()) {
802                finalInval = webViewRect;
803                retVal = true;
804            } else {
805                finalInval.setX(webViewRect.x() + inval.x());
806                finalInval.setY(webViewRect.y() + titlebarHeight + inval.y());
807                finalInval.setWidth(inval.width());
808                finalInval.setHeight(inval.height());
809            }
810            info->dirtyLeft = finalInval.x();
811            info->dirtyTop = finalInval.y();
812            info->dirtyRight = finalInval.maxX();
813            info->dirtyBottom = finalInval.maxY();
814        }
815        // return 1 if invalidation needed, 0 otherwise
816        return retVal ? 1 : 0;
817    }
818    void updateRect(WebCore::IntRect& _viewRect) {
819        viewRect = _viewRect;
820    }
821    void updateViewRect(WebCore::IntRect& _viewRect) {
822        webViewRect = _viewRect;
823    }
824    void updateScale(float _scale) {
825        scale = _scale;
826    }
827    private:
828    WebView* wvInstance;
829    bool (WebView::*funcPtr)(WebCore::IntRect&, WebCore::IntRect*,
830            WebCore::IntRect&, int, WebCore::IntRect&, float, int);
831    WebCore::IntRect viewRect;
832    WebCore::IntRect webViewRect;
833    jfloat scale;
834    jint extras;
835};
836
837/*
838 * Native JNI methods
839 */
840static int nativeCacheHitFramePointer(JNIEnv *env, jobject obj)
841{
842    return 0;
843}
844
845static jobject nativeCacheHitNodeBounds(JNIEnv *env, jobject obj)
846{
847    return 0;
848}
849
850static int nativeCacheHitNodePointer(JNIEnv *env, jobject obj)
851{
852    return 0;
853}
854
855static bool nativeCacheHitIsPlugin(JNIEnv *env, jobject obj)
856{
857    return false;
858}
859
860static void nativeClearCursor(JNIEnv *env, jobject obj)
861{
862}
863
864static void nativeCreate(JNIEnv *env, jobject obj, int viewImpl,
865                         jstring drawableDir, jboolean isHighEndGfx)
866{
867    WTF::String dir = jstringToWtfString(env, drawableDir);
868    new WebView(env, obj, viewImpl, dir, isHighEndGfx);
869    // NEED THIS OR SOMETHING LIKE IT!
870    //Release(obj);
871}
872
873static jint nativeCursorFramePointer(JNIEnv *env, jobject obj)
874{
875    return 0;
876}
877
878static bool focusCandidateHasNextTextfield(JNIEnv *env, jobject obj)
879{
880    return false;
881}
882
883static jboolean nativePageShouldHandleShiftAndArrows(JNIEnv *env, jobject obj)
884{
885    return true;
886}
887
888static jobject nativeCursorNodeBounds(JNIEnv *env, jobject obj)
889{
890    return 0;
891}
892
893static jint nativeCursorNodePointer(JNIEnv *env, jobject obj)
894{
895    return 0;
896}
897
898static jobject nativeCursorPosition(JNIEnv *env, jobject obj)
899{
900    return 0;
901}
902
903static WebCore::IntRect jrect_to_webrect(JNIEnv* env, jobject obj)
904{
905    if (obj) {
906        int L, T, R, B;
907        GraphicsJNI::get_jrect(env, obj, &L, &T, &R, &B);
908        return WebCore::IntRect(L, T, R - L, B - T);
909    } else
910        return WebCore::IntRect();
911}
912
913static SkRect jrectf_to_rect(JNIEnv* env, jobject obj)
914{
915    SkRect rect = SkRect::MakeEmpty();
916    if (obj)
917        GraphicsJNI::jrectf_to_rect(env, obj, &rect);
918    return rect;
919}
920
921static bool nativeCursorIntersects(JNIEnv *env, jobject obj, jobject visRect)
922{
923    return false;
924}
925
926static bool nativeCursorIsAnchor(JNIEnv *env, jobject obj)
927{
928    return false;
929}
930
931static bool nativeCursorIsTextInput(JNIEnv *env, jobject obj)
932{
933    return false;
934}
935
936static jobject nativeCursorText(JNIEnv *env, jobject obj)
937{
938    return 0;
939}
940
941static void nativeDebugDump(JNIEnv *env, jobject obj)
942{
943}
944
945static jint nativeDraw(JNIEnv *env, jobject obj, jobject canv,
946        jobject visible, jint color,
947        jint extras, jboolean split) {
948    SkCanvas* canvas = GraphicsJNI::getNativeCanvas(env, canv);
949    WebView* webView = GET_NATIVE_VIEW(env, obj);
950    SkRect visibleRect = jrectf_to_rect(env, visible);
951    webView->setVisibleRect(visibleRect);
952    PictureSet* pictureSet = webView->draw(canvas, color,
953            static_cast<WebView::DrawExtras>(extras), split);
954    return reinterpret_cast<jint>(pictureSet);
955}
956
957static jint nativeGetDrawGLFunction(JNIEnv *env, jobject obj, jint nativeView,
958                                    jobject jrect, jobject jviewrect,
959                                    jobject jvisiblerect,
960                                    jfloat scale, jint extras) {
961    WebCore::IntRect viewRect = jrect_to_webrect(env, jrect);
962    WebView *wvInstance = (WebView*) nativeView;
963    SkRect visibleRect = jrectf_to_rect(env, jvisiblerect);
964    wvInstance->setVisibleRect(visibleRect);
965
966    GLDrawFunctor* functor = new GLDrawFunctor(wvInstance,
967            &android::WebView::drawGL, viewRect, scale, extras);
968    wvInstance->setFunctor((Functor*) functor);
969
970    WebCore::IntRect webViewRect = jrect_to_webrect(env, jviewrect);
971    functor->updateViewRect(webViewRect);
972
973    return (jint)functor;
974}
975
976static void nativeUpdateDrawGLFunction(JNIEnv *env, jobject obj, jobject jrect,
977        jobject jviewrect, jobject jvisiblerect, jfloat scale) {
978    WebView *wvInstance = GET_NATIVE_VIEW(env, obj);
979    if (wvInstance) {
980        GLDrawFunctor* functor = (GLDrawFunctor*) wvInstance->getFunctor();
981        if (functor) {
982            WebCore::IntRect viewRect = jrect_to_webrect(env, jrect);
983            functor->updateRect(viewRect);
984
985            SkRect visibleRect = jrectf_to_rect(env, jvisiblerect);
986            wvInstance->setVisibleRect(visibleRect);
987
988            WebCore::IntRect webViewRect = jrect_to_webrect(env, jviewrect);
989            functor->updateViewRect(webViewRect);
990
991            functor->updateScale(scale);
992        }
993    }
994}
995
996static bool nativeEvaluateLayersAnimations(JNIEnv *env, jobject obj, jint nativeView)
997{
998    // only call in software rendering, initialize and evaluate animations
999#if USE(ACCELERATED_COMPOSITING)
1000    LayerAndroid* root = ((WebView*)nativeView)->compositeRoot();
1001    if (root) {
1002        root->initAnimations();
1003        return root->evaluateAnimations();
1004    }
1005#endif
1006    return false;
1007}
1008
1009static bool nativeSetBaseLayer(JNIEnv *env, jobject obj, jint nativeView, jint layer, jobject inval,
1010                               jboolean showVisualIndicator,
1011                               jboolean isPictureAfterFirstLayout)
1012{
1013    BaseLayerAndroid* layerImpl = reinterpret_cast<BaseLayerAndroid*>(layer);
1014    SkRegion invalRegion;
1015    if (inval)
1016        invalRegion = *GraphicsJNI::getNativeRegion(env, inval);
1017    return ((WebView*)nativeView)->setBaseLayer(layerImpl, invalRegion, showVisualIndicator,
1018                                                isPictureAfterFirstLayout);
1019}
1020
1021static BaseLayerAndroid* nativeGetBaseLayer(JNIEnv *env, jobject obj)
1022{
1023    return GET_NATIVE_VIEW(env, obj)->getBaseLayer();
1024}
1025
1026static void nativeReplaceBaseContent(JNIEnv *env, jobject obj, jint content)
1027{
1028    PictureSet* set = reinterpret_cast<PictureSet*>(content);
1029    GET_NATIVE_VIEW(env, obj)->replaceBaseContent(set);
1030}
1031
1032static void nativeCopyBaseContentToPicture(JNIEnv *env, jobject obj, jobject pict)
1033{
1034    SkPicture* picture = GraphicsJNI::getNativePicture(env, pict);
1035    GET_NATIVE_VIEW(env, obj)->copyBaseContentToPicture(picture);
1036}
1037
1038static bool nativeHasContent(JNIEnv *env, jobject obj)
1039{
1040    return GET_NATIVE_VIEW(env, obj)->hasContent();
1041}
1042
1043static jobject nativeImageURI(JNIEnv *env, jobject obj, jint x, jint y)
1044{
1045    return 0;
1046}
1047
1048static jint nativeFocusCandidateFramePointer(JNIEnv *env, jobject obj)
1049{
1050    return 0;
1051}
1052
1053static bool nativeFocusCandidateIsEditableText(JNIEnv* env, jobject obj,
1054        jint nativeClass)
1055{
1056    return false;
1057}
1058
1059static bool nativeFocusCandidateIsPassword(JNIEnv *env, jobject obj)
1060{
1061    return false;
1062}
1063
1064static bool nativeFocusCandidateIsRtlText(JNIEnv *env, jobject obj)
1065{
1066    return false;
1067}
1068
1069static bool nativeFocusCandidateIsTextInput(JNIEnv *env, jobject obj)
1070{
1071    return false;
1072}
1073
1074static jint nativeFocusCandidateMaxLength(JNIEnv *env, jobject obj)
1075{
1076    return 0;
1077}
1078
1079static jint nativeFocusCandidateIsAutoComplete(JNIEnv *env, jobject obj)
1080{
1081    return 0;
1082}
1083
1084static jobject nativeFocusCandidateName(JNIEnv *env, jobject obj)
1085{
1086    return false;
1087}
1088
1089static jobject nativeFocusCandidateNodeBounds(JNIEnv *env, jobject obj)
1090{
1091    return 0;
1092}
1093
1094static jobject nativeFocusCandidatePaddingRect(JNIEnv *env, jobject obj)
1095{
1096    return 0;
1097}
1098
1099static jint nativeFocusCandidatePointer(JNIEnv *env, jobject obj)
1100{
1101    return 0;
1102}
1103
1104static jint nativeFocusCandidateIsSpellcheck(JNIEnv *env, jobject obj)
1105{
1106    return 0;
1107}
1108
1109static jobject nativeFocusCandidateText(JNIEnv *env, jobject obj)
1110{
1111    return 0;
1112}
1113
1114static int nativeFocusCandidateLineHeight(JNIEnv *env, jobject obj)
1115{
1116    return 0;
1117}
1118
1119static jfloat nativeFocusCandidateTextSize(JNIEnv *env, jobject obj)
1120{
1121    return 0.f;
1122}
1123
1124static int nativeFocusCandidateType(JNIEnv *env, jobject obj)
1125{
1126    return 0;
1127}
1128
1129static int nativeFocusCandidateLayerId(JNIEnv *env, jobject obj)
1130{
1131    return 0;
1132}
1133
1134static bool nativeFocusIsPlugin(JNIEnv *env, jobject obj)
1135{
1136    return false;
1137}
1138
1139static jobject nativeFocusNodeBounds(JNIEnv *env, jobject obj)
1140{
1141    return 0;
1142}
1143
1144static jint nativeFocusNodePointer(JNIEnv *env, jobject obj)
1145{
1146    return 0;
1147}
1148
1149static bool nativeCursorWantsKeyEvents(JNIEnv* env, jobject jwebview) {
1150    return false;
1151}
1152
1153static void nativeHideCursor(JNIEnv *env, jobject obj)
1154{
1155}
1156
1157static void nativeSelectBestAt(JNIEnv *env, jobject obj, jobject jrect)
1158{
1159}
1160
1161static void nativeSelectAt(JNIEnv *env, jobject obj, jint x, jint y)
1162{
1163}
1164
1165static jobject nativeLayerBounds(JNIEnv* env, jobject obj, jint jlayer)
1166{
1167    SkRect r;
1168#if USE(ACCELERATED_COMPOSITING)
1169    LayerAndroid* layer = (LayerAndroid*) jlayer;
1170    r = layer->bounds();
1171#else
1172    r.setEmpty();
1173#endif
1174    SkIRect irect;
1175    r.round(&irect);
1176    jclass rectClass = env->FindClass("android/graphics/Rect");
1177    jmethodID init = env->GetMethodID(rectClass, "<init>", "(IIII)V");
1178    jobject rect = env->NewObject(rectClass, init, irect.fLeft, irect.fTop,
1179        irect.fRight, irect.fBottom);
1180    env->DeleteLocalRef(rectClass);
1181    return rect;
1182}
1183
1184static jobject nativeSubtractLayers(JNIEnv* env, jobject obj, jobject jrect)
1185{
1186    SkIRect irect = jrect_to_webrect(env, jrect);
1187#if USE(ACCELERATED_COMPOSITING)
1188    LayerAndroid* root = GET_NATIVE_VIEW(env, obj)->compositeRoot();
1189    if (root) {
1190        SkRect rect;
1191        rect.set(irect);
1192        rect = root->subtractLayers(rect);
1193        rect.round(&irect);
1194    }
1195#endif
1196    jclass rectClass = env->FindClass("android/graphics/Rect");
1197    jmethodID init = env->GetMethodID(rectClass, "<init>", "(IIII)V");
1198    jobject rect = env->NewObject(rectClass, init, irect.fLeft, irect.fTop,
1199        irect.fRight, irect.fBottom);
1200    env->DeleteLocalRef(rectClass);
1201    return rect;
1202}
1203
1204static jint nativeTextGeneration(JNIEnv *env, jobject obj)
1205{
1206    return 0;
1207}
1208
1209static bool nativePointInNavCache(JNIEnv *env, jobject obj,
1210    int x, int y, int slop)
1211{
1212    return false;
1213}
1214
1215static bool nativeMotionUp(JNIEnv *env, jobject obj,
1216    int x, int y, int slop)
1217{
1218    return false;
1219}
1220
1221static bool nativeHasCursorNode(JNIEnv *env, jobject obj)
1222{
1223    return false;
1224}
1225
1226static bool nativeHasFocusNode(JNIEnv *env, jobject obj)
1227{
1228    return false;
1229}
1230
1231static bool nativeMoveCursor(JNIEnv *env, jobject obj,
1232    int key, int count, bool ignoreScroll)
1233{
1234    return false;
1235}
1236
1237static void nativeSetFindIsUp(JNIEnv *env, jobject obj, jboolean isUp)
1238{
1239    WebView* view = GET_NATIVE_VIEW(env, obj);
1240    ALOG_ASSERT(view, "view not set in %s", __FUNCTION__);
1241    view->setFindIsUp(isUp);
1242}
1243
1244static void nativeShowCursorTimed(JNIEnv *env, jobject obj)
1245{
1246}
1247
1248static void nativeSetHeightCanMeasure(JNIEnv *env, jobject obj, bool measure)
1249{
1250    WebView* view = GET_NATIVE_VIEW(env, obj);
1251    ALOG_ASSERT(view, "view not set in nativeSetHeightCanMeasure");
1252    view->setHeightCanMeasure(measure);
1253}
1254
1255static jobject nativeGetCursorRingBounds(JNIEnv *env, jobject obj)
1256{
1257    return 0;
1258}
1259
1260static void nativeUpdateCachedTextfield(JNIEnv *env, jobject obj, jstring updatedText, jint generation)
1261{
1262}
1263
1264static jint nativeGetBlockLeftEdge(JNIEnv *env, jobject obj, jint x, jint y,
1265        jfloat scale)
1266{
1267    return -1;
1268}
1269
1270static void nativeDestroy(JNIEnv *env, jobject obj)
1271{
1272    WebView* view = GET_NATIVE_VIEW(env, obj);
1273    ALOGD("nativeDestroy view: %p", view);
1274    ALOG_ASSERT(view, "view not set in nativeDestroy");
1275    delete view;
1276}
1277
1278static void nativeStopGL(JNIEnv *env, jobject obj)
1279{
1280    GET_NATIVE_VIEW(env, obj)->stopGL();
1281}
1282
1283static bool nativeMoveCursorToNextTextInput(JNIEnv *env, jobject obj)
1284{
1285    return false;
1286}
1287
1288static int nativeMoveGeneration(JNIEnv *env, jobject obj)
1289{
1290    WebView* view = GET_NATIVE_VIEW(env, obj);
1291    if (!view)
1292        return 0;
1293    return view->moveGeneration();
1294}
1295
1296static jobject nativeGetSelection(JNIEnv *env, jobject obj)
1297{
1298    WebView* view = GET_NATIVE_VIEW(env, obj);
1299    ALOG_ASSERT(view, "view not set in %s", __FUNCTION__);
1300    String selection = view->getSelection();
1301    return wtfStringToJstring(env, selection);
1302}
1303
1304static void nativeDiscardAllTextures(JNIEnv *env, jobject obj)
1305{
1306    //discard all textures for debugging/test purposes, but not gl backing memory
1307    bool allTextures = true, deleteGLTextures = false;
1308    TilesManager::instance()->discardTextures(allTextures, deleteGLTextures);
1309}
1310
1311static void nativeTileProfilingStart(JNIEnv *env, jobject obj)
1312{
1313    TilesManager::instance()->getProfiler()->start();
1314}
1315
1316static float nativeTileProfilingStop(JNIEnv *env, jobject obj)
1317{
1318    return TilesManager::instance()->getProfiler()->stop();
1319}
1320
1321static void nativeTileProfilingClear(JNIEnv *env, jobject obj)
1322{
1323    TilesManager::instance()->getProfiler()->clear();
1324}
1325
1326static int nativeTileProfilingNumFrames(JNIEnv *env, jobject obj)
1327{
1328    return TilesManager::instance()->getProfiler()->numFrames();
1329}
1330
1331static int nativeTileProfilingNumTilesInFrame(JNIEnv *env, jobject obj, int frame)
1332{
1333    return TilesManager::instance()->getProfiler()->numTilesInFrame(frame);
1334}
1335
1336static int nativeTileProfilingGetInt(JNIEnv *env, jobject obj, int frame, int tile, jstring jkey)
1337{
1338    WTF::String key = jstringToWtfString(env, jkey);
1339    TileProfileRecord* record = TilesManager::instance()->getProfiler()->getTile(frame, tile);
1340
1341    if (key == "left")
1342        return record->left;
1343    if (key == "top")
1344        return record->top;
1345    if (key == "right")
1346        return record->right;
1347    if (key == "bottom")
1348        return record->bottom;
1349    if (key == "level")
1350        return record->level;
1351    if (key == "isReady")
1352        return record->isReady ? 1 : 0;
1353    return -1;
1354}
1355
1356static float nativeTileProfilingGetFloat(JNIEnv *env, jobject obj, int frame, int tile, jstring jkey)
1357{
1358    TileProfileRecord* record = TilesManager::instance()->getProfiler()->getTile(frame, tile);
1359    return record->scale;
1360}
1361
1362#ifdef ANDROID_DUMP_DISPLAY_TREE
1363static void dumpToFile(const char text[], void* file) {
1364    fwrite(text, 1, strlen(text), reinterpret_cast<FILE*>(file));
1365    fwrite("\n", 1, 1, reinterpret_cast<FILE*>(file));
1366}
1367#endif
1368
1369static bool nativeSetProperty(JNIEnv *env, jobject obj, jstring jkey, jstring jvalue)
1370{
1371    WTF::String key = jstringToWtfString(env, jkey);
1372    WTF::String value = jstringToWtfString(env, jvalue);
1373    if (key == "inverted") {
1374        bool shouldInvert = (value == "true");
1375        TilesManager::instance()->setInvertedScreen(shouldInvert);
1376        return true;
1377    }
1378    else if (key == "inverted_contrast") {
1379        float contrast = value.toFloat();
1380        TilesManager::instance()->setInvertedScreenContrast(contrast);
1381        return true;
1382    }
1383    else if (key == "enable_cpu_upload_path") {
1384        TilesManager::instance()->transferQueue()->setTextureUploadType(
1385            value == "true" ? CpuUpload : GpuUpload);
1386        return true;
1387    }
1388    else if (key == "use_minimal_memory") {
1389        TilesManager::instance()->setUseMinimalMemory(value == "true");
1390        return true;
1391    }
1392    else if (key == "use_double_buffering") {
1393        TilesManager::instance()->setUseDoubleBuffering(value == "true");
1394        return true;
1395    }
1396    else if (key == "tree_updates") {
1397        TilesManager::instance()->clearContentUpdates();
1398        return true;
1399    }
1400    return false;
1401}
1402
1403static jstring nativeGetProperty(JNIEnv *env, jobject obj, jstring jkey)
1404{
1405    WTF::String key = jstringToWtfString(env, jkey);
1406    if (key == "tree_updates") {
1407        int updates = TilesManager::instance()->getContentUpdates();
1408        WTF::String wtfUpdates = WTF::String::number(updates);
1409        return wtfStringToJstring(env, wtfUpdates);
1410    }
1411    return 0;
1412}
1413
1414static void nativeOnTrimMemory(JNIEnv *env, jobject obj, jint level)
1415{
1416    if (TilesManager::hardwareAccelerationEnabled()) {
1417        // When we got TRIM_MEMORY_MODERATE or TRIM_MEMORY_COMPLETE, we should
1418        // make sure the transfer queue is empty and then abandon the Surface
1419        // Texture to avoid ANR b/c framework may destroy the EGL context.
1420        // Refer to WindowManagerImpl.java for conditions we followed.
1421        TilesManager* tilesManager = TilesManager::instance();
1422        if (level >= TRIM_MEMORY_MODERATE
1423            && !tilesManager->highEndGfx()) {
1424            ALOGD("OnTrimMemory with EGL Context %p", eglGetCurrentContext());
1425            tilesManager->transferQueue()->emptyQueue();
1426            tilesManager->shader()->cleanupGLResources();
1427            tilesManager->videoLayerManager()->cleanupGLResources();
1428        }
1429
1430        bool freeAllTextures = (level > TRIM_MEMORY_UI_HIDDEN), glTextures = true;
1431        tilesManager->discardTextures(freeAllTextures, glTextures);
1432    }
1433}
1434
1435static void nativeDumpDisplayTree(JNIEnv* env, jobject jwebview, jstring jurl)
1436{
1437#ifdef ANDROID_DUMP_DISPLAY_TREE
1438    WebView* view = GET_NATIVE_VIEW(env, jwebview);
1439    ALOG_ASSERT(view, "view not set in %s", __FUNCTION__);
1440
1441    if (view && view->getWebViewCore()) {
1442        FILE* file = fopen(DISPLAY_TREE_LOG_FILE, "w");
1443        if (file) {
1444            SkFormatDumper dumper(dumpToFile, file);
1445            // dump the URL
1446            if (jurl) {
1447                const char* str = env->GetStringUTFChars(jurl, 0);
1448                SkDebugf("Dumping %s to %s\n", str, DISPLAY_TREE_LOG_FILE);
1449                dumpToFile(str, file);
1450                env->ReleaseStringUTFChars(jurl, str);
1451            }
1452            // now dump the display tree
1453            SkDumpCanvas canvas(&dumper);
1454            // this will playback the picture into the canvas, which will
1455            // spew its contents to the dumper
1456            view->draw(&canvas, 0, WebView::DrawExtrasNone, false);
1457            // we're done with the file now
1458            fwrite("\n", 1, 1, file);
1459            fclose(file);
1460        }
1461#if USE(ACCELERATED_COMPOSITING)
1462        const LayerAndroid* rootLayer = view->compositeRoot();
1463        if (rootLayer) {
1464          FILE* file = fopen(LAYERS_TREE_LOG_FILE,"w");
1465          if (file) {
1466              rootLayer->dumpLayers(file, 0);
1467              fclose(file);
1468          }
1469        }
1470#endif
1471    }
1472#endif
1473}
1474
1475static int nativeScrollableLayer(JNIEnv* env, jobject jwebview, jint x, jint y,
1476    jobject rect, jobject bounds)
1477{
1478    WebView* view = GET_NATIVE_VIEW(env, jwebview);
1479    ALOG_ASSERT(view, "view not set in %s", __FUNCTION__);
1480    SkIRect nativeRect, nativeBounds;
1481    int id = view->scrollableLayer(x, y, &nativeRect, &nativeBounds);
1482    if (rect)
1483        GraphicsJNI::irect_to_jrect(nativeRect, env, rect);
1484    if (bounds)
1485        GraphicsJNI::irect_to_jrect(nativeBounds, env, bounds);
1486    return id;
1487}
1488
1489static bool nativeScrollLayer(JNIEnv* env, jobject obj, jint layerId, jint x,
1490        jint y)
1491{
1492#if ENABLE(ANDROID_OVERFLOW_SCROLL)
1493    WebView* view = GET_NATIVE_VIEW(env, obj);
1494    view->scrollLayer(layerId, x, y);
1495
1496    //TODO: the below only needed for the SW rendering path
1497    LayerAndroid* root = view->compositeRoot();
1498    if (!root)
1499        return false;
1500    LayerAndroid* layer = root->findById(layerId);
1501    if (!layer || !layer->contentIsScrollable())
1502        return false;
1503    return static_cast<ScrollableLayerAndroid*>(layer)->scrollTo(x, y);
1504#endif
1505    return false;
1506}
1507
1508static void nativeSetIsScrolling(JNIEnv* env, jobject jwebview, jboolean isScrolling)
1509{
1510    WebView* view = GET_NATIVE_VIEW(env, jwebview);
1511    ALOG_ASSERT(view, "view not set in %s", __FUNCTION__);
1512    view->setIsScrolling(isScrolling);
1513}
1514
1515static void nativeUseHardwareAccelSkia(JNIEnv*, jobject, jboolean enabled)
1516{
1517    BaseRenderer::setCurrentRendererType(enabled ? BaseRenderer::Ganesh : BaseRenderer::Raster);
1518}
1519
1520static int nativeGetBackgroundColor(JNIEnv* env, jobject obj)
1521{
1522    WebView* view = GET_NATIVE_VIEW(env, obj);
1523    BaseLayerAndroid* baseLayer = view->getBaseLayer();
1524    if (baseLayer) {
1525        WebCore::Color color = baseLayer->getBackgroundColor();
1526        if (color.isValid())
1527            return SkColorSetARGB(color.alpha(), color.red(),
1528                                  color.green(), color.blue());
1529    }
1530    return SK_ColorWHITE;
1531}
1532
1533static void nativeSetPauseDrawing(JNIEnv *env, jobject obj, jint nativeView,
1534                                      jboolean pause)
1535{
1536    ((WebView*)nativeView)->m_isDrawingPaused = pause;
1537}
1538
1539static bool nativeDisableNavcache(JNIEnv *env, jobject obj)
1540{
1541    return true;
1542}
1543
1544static void nativeSetTextSelection(JNIEnv *env, jobject obj, jint nativeView,
1545                                   jint selectionPtr)
1546{
1547    SelectText* selection = reinterpret_cast<SelectText*>(selectionPtr);
1548    reinterpret_cast<WebView*>(nativeView)->setTextSelection(selection);
1549}
1550
1551static jint nativeGetHandleLayerId(JNIEnv *env, jobject obj, jint nativeView,
1552                                     jint handleIndex, jobject cursorRect)
1553{
1554    WebView* webview = reinterpret_cast<WebView*>(nativeView);
1555    SkIRect nativeRect;
1556    int layerId = webview->getHandleLayerId((SelectText::HandleId) handleIndex, nativeRect);
1557    if (cursorRect)
1558        GraphicsJNI::irect_to_jrect(nativeRect, env, cursorRect);
1559    return layerId;
1560}
1561
1562static jboolean nativeIsBaseFirst(JNIEnv *env, jobject obj, jint nativeView)
1563{
1564    WebView* webview = reinterpret_cast<WebView*>(nativeView);
1565    SelectText* select = static_cast<SelectText*>(
1566            webview->getDrawExtra(WebView::DrawExtrasSelection));
1567    return select ? select->isBaseFirst() : false;
1568}
1569
1570/*
1571 * JNI registration
1572 */
1573static JNINativeMethod gJavaWebViewMethods[] = {
1574    { "nativeCacheHitFramePointer", "()I",
1575        (void*) nativeCacheHitFramePointer },
1576    { "nativeCacheHitIsPlugin", "()Z",
1577        (void*) nativeCacheHitIsPlugin },
1578    { "nativeCacheHitNodeBounds", "()Landroid/graphics/Rect;",
1579        (void*) nativeCacheHitNodeBounds },
1580    { "nativeCacheHitNodePointer", "()I",
1581        (void*) nativeCacheHitNodePointer },
1582    { "nativeClearCursor", "()V",
1583        (void*) nativeClearCursor },
1584    { "nativeCreate", "(ILjava/lang/String;Z)V",
1585        (void*) nativeCreate },
1586    { "nativeCursorFramePointer", "()I",
1587        (void*) nativeCursorFramePointer },
1588    { "nativePageShouldHandleShiftAndArrows", "()Z",
1589        (void*) nativePageShouldHandleShiftAndArrows },
1590    { "nativeCursorNodeBounds", "()Landroid/graphics/Rect;",
1591        (void*) nativeCursorNodeBounds },
1592    { "nativeCursorNodePointer", "()I",
1593        (void*) nativeCursorNodePointer },
1594    { "nativeCursorIntersects", "(Landroid/graphics/Rect;)Z",
1595        (void*) nativeCursorIntersects },
1596    { "nativeCursorIsAnchor", "()Z",
1597        (void*) nativeCursorIsAnchor },
1598    { "nativeCursorIsTextInput", "()Z",
1599        (void*) nativeCursorIsTextInput },
1600    { "nativeCursorPosition", "()Landroid/graphics/Point;",
1601        (void*) nativeCursorPosition },
1602    { "nativeCursorText", "()Ljava/lang/String;",
1603        (void*) nativeCursorText },
1604    { "nativeCursorWantsKeyEvents", "()Z",
1605        (void*)nativeCursorWantsKeyEvents },
1606    { "nativeDebugDump", "()V",
1607        (void*) nativeDebugDump },
1608    { "nativeDestroy", "()V",
1609        (void*) nativeDestroy },
1610    { "nativeDraw", "(Landroid/graphics/Canvas;Landroid/graphics/RectF;IIZ)I",
1611        (void*) nativeDraw },
1612    { "nativeGetDrawGLFunction", "(ILandroid/graphics/Rect;Landroid/graphics/Rect;Landroid/graphics/RectF;FI)I",
1613        (void*) nativeGetDrawGLFunction },
1614    { "nativeUpdateDrawGLFunction", "(Landroid/graphics/Rect;Landroid/graphics/Rect;Landroid/graphics/RectF;F)V",
1615        (void*) nativeUpdateDrawGLFunction },
1616    { "nativeDumpDisplayTree", "(Ljava/lang/String;)V",
1617        (void*) nativeDumpDisplayTree },
1618    { "nativeEvaluateLayersAnimations", "(I)Z",
1619        (void*) nativeEvaluateLayersAnimations },
1620    { "nativeFocusCandidateFramePointer", "()I",
1621        (void*) nativeFocusCandidateFramePointer },
1622    { "nativeFocusCandidateHasNextTextfield", "()Z",
1623        (void*) focusCandidateHasNextTextfield },
1624    { "nativeFocusCandidateIsPassword", "()Z",
1625        (void*) nativeFocusCandidateIsPassword },
1626    { "nativeFocusCandidateIsRtlText", "()Z",
1627        (void*) nativeFocusCandidateIsRtlText },
1628    { "nativeFocusCandidateIsTextInput", "()Z",
1629        (void*) nativeFocusCandidateIsTextInput },
1630    { "nativeFocusCandidateLineHeight", "()I",
1631        (void*) nativeFocusCandidateLineHeight },
1632    { "nativeFocusCandidateMaxLength", "()I",
1633        (void*) nativeFocusCandidateMaxLength },
1634    { "nativeFocusCandidateIsAutoComplete", "()Z",
1635        (void*) nativeFocusCandidateIsAutoComplete },
1636    { "nativeFocusCandidateIsSpellcheck", "()Z",
1637        (void*) nativeFocusCandidateIsSpellcheck },
1638    { "nativeFocusCandidateName", "()Ljava/lang/String;",
1639        (void*) nativeFocusCandidateName },
1640    { "nativeFocusCandidateNodeBounds", "()Landroid/graphics/Rect;",
1641        (void*) nativeFocusCandidateNodeBounds },
1642    { "nativeFocusCandidatePaddingRect", "()Landroid/graphics/Rect;",
1643        (void*) nativeFocusCandidatePaddingRect },
1644    { "nativeFocusCandidatePointer", "()I",
1645        (void*) nativeFocusCandidatePointer },
1646    { "nativeFocusCandidateText", "()Ljava/lang/String;",
1647        (void*) nativeFocusCandidateText },
1648    { "nativeFocusCandidateTextSize", "()F",
1649        (void*) nativeFocusCandidateTextSize },
1650    { "nativeFocusCandidateType", "()I",
1651        (void*) nativeFocusCandidateType },
1652    { "nativeFocusCandidateLayerId", "()I",
1653        (void*) nativeFocusCandidateLayerId },
1654    { "nativeFocusIsPlugin", "()Z",
1655        (void*) nativeFocusIsPlugin },
1656    { "nativeFocusNodeBounds", "()Landroid/graphics/Rect;",
1657        (void*) nativeFocusNodeBounds },
1658    { "nativeFocusNodePointer", "()I",
1659        (void*) nativeFocusNodePointer },
1660    { "nativeGetCursorRingBounds", "()Landroid/graphics/Rect;",
1661        (void*) nativeGetCursorRingBounds },
1662    { "nativeGetSelection", "()Ljava/lang/String;",
1663        (void*) nativeGetSelection },
1664    { "nativeHasCursorNode", "()Z",
1665        (void*) nativeHasCursorNode },
1666    { "nativeHasFocusNode", "()Z",
1667        (void*) nativeHasFocusNode },
1668    { "nativeHideCursor", "()V",
1669        (void*) nativeHideCursor },
1670    { "nativeImageURI", "(II)Ljava/lang/String;",
1671        (void*) nativeImageURI },
1672    { "nativeLayerBounds", "(I)Landroid/graphics/Rect;",
1673        (void*) nativeLayerBounds },
1674    { "nativeMotionUp", "(III)Z",
1675        (void*) nativeMotionUp },
1676    { "nativeMoveCursor", "(IIZ)Z",
1677        (void*) nativeMoveCursor },
1678    { "nativeMoveCursorToNextTextInput", "()Z",
1679        (void*) nativeMoveCursorToNextTextInput },
1680    { "nativeMoveGeneration", "()I",
1681        (void*) nativeMoveGeneration },
1682    { "nativePointInNavCache", "(III)Z",
1683        (void*) nativePointInNavCache },
1684    { "nativeSelectBestAt", "(Landroid/graphics/Rect;)V",
1685        (void*) nativeSelectBestAt },
1686    { "nativeSelectAt", "(II)V",
1687        (void*) nativeSelectAt },
1688    { "nativeSetFindIsUp", "(Z)V",
1689        (void*) nativeSetFindIsUp },
1690    { "nativeSetHeightCanMeasure", "(Z)V",
1691        (void*) nativeSetHeightCanMeasure },
1692    { "nativeSetBaseLayer", "(IILandroid/graphics/Region;ZZ)Z",
1693        (void*) nativeSetBaseLayer },
1694    { "nativeGetBaseLayer", "()I",
1695        (void*) nativeGetBaseLayer },
1696    { "nativeReplaceBaseContent", "(I)V",
1697        (void*) nativeReplaceBaseContent },
1698    { "nativeCopyBaseContentToPicture", "(Landroid/graphics/Picture;)V",
1699        (void*) nativeCopyBaseContentToPicture },
1700    { "nativeHasContent", "()Z",
1701        (void*) nativeHasContent },
1702    { "nativeShowCursorTimed", "()V",
1703        (void*) nativeShowCursorTimed },
1704    { "nativeDiscardAllTextures", "()V",
1705        (void*) nativeDiscardAllTextures },
1706    { "nativeTileProfilingStart", "()V",
1707        (void*) nativeTileProfilingStart },
1708    { "nativeTileProfilingStop", "()F",
1709        (void*) nativeTileProfilingStop },
1710    { "nativeTileProfilingClear", "()V",
1711        (void*) nativeTileProfilingClear },
1712    { "nativeTileProfilingNumFrames", "()I",
1713        (void*) nativeTileProfilingNumFrames },
1714    { "nativeTileProfilingNumTilesInFrame", "(I)I",
1715        (void*) nativeTileProfilingNumTilesInFrame },
1716    { "nativeTileProfilingGetInt", "(IILjava/lang/String;)I",
1717        (void*) nativeTileProfilingGetInt },
1718    { "nativeTileProfilingGetFloat", "(IILjava/lang/String;)F",
1719        (void*) nativeTileProfilingGetFloat },
1720    { "nativeStopGL", "()V",
1721        (void*) nativeStopGL },
1722    { "nativeSubtractLayers", "(Landroid/graphics/Rect;)Landroid/graphics/Rect;",
1723        (void*) nativeSubtractLayers },
1724    { "nativeTextGeneration", "()I",
1725        (void*) nativeTextGeneration },
1726    { "nativeUpdateCachedTextfield", "(Ljava/lang/String;I)V",
1727        (void*) nativeUpdateCachedTextfield },
1728    { "nativeGetBlockLeftEdge", "(IIF)I",
1729        (void*) nativeGetBlockLeftEdge },
1730    { "nativeScrollableLayer", "(IILandroid/graphics/Rect;Landroid/graphics/Rect;)I",
1731        (void*) nativeScrollableLayer },
1732    { "nativeScrollLayer", "(III)Z",
1733        (void*) nativeScrollLayer },
1734    { "nativeSetIsScrolling", "(Z)V",
1735        (void*) nativeSetIsScrolling },
1736    { "nativeUseHardwareAccelSkia", "(Z)V",
1737        (void*) nativeUseHardwareAccelSkia },
1738    { "nativeGetBackgroundColor", "()I",
1739        (void*) nativeGetBackgroundColor },
1740    { "nativeSetProperty", "(Ljava/lang/String;Ljava/lang/String;)Z",
1741        (void*) nativeSetProperty },
1742    { "nativeGetProperty", "(Ljava/lang/String;)Ljava/lang/String;",
1743        (void*) nativeGetProperty },
1744    { "nativeOnTrimMemory", "(I)V",
1745        (void*) nativeOnTrimMemory },
1746    { "nativeSetPauseDrawing", "(IZ)V",
1747        (void*) nativeSetPauseDrawing },
1748    { "nativeDisableNavcache", "()Z",
1749        (void*) nativeDisableNavcache },
1750    { "nativeFocusCandidateIsEditableText", "(I)Z",
1751        (void*) nativeFocusCandidateIsEditableText },
1752    { "nativeSetTextSelection", "(II)V",
1753        (void*) nativeSetTextSelection },
1754    { "nativeGetHandleLayerId", "(IILandroid/graphics/Rect;)I",
1755        (void*) nativeGetHandleLayerId },
1756    { "nativeIsBaseFirst", "(I)Z",
1757        (void*) nativeIsBaseFirst },
1758};
1759
1760int registerWebView(JNIEnv* env)
1761{
1762    jclass clazz = env->FindClass("android/webkit/WebViewClassic");
1763    ALOG_ASSERT(clazz, "Unable to find class android/webkit/WebViewClassic");
1764    gWebViewField = env->GetFieldID(clazz, "mNativeClass", "I");
1765    ALOG_ASSERT(gWebViewField, "Unable to find android/webkit/WebViewClassic.mNativeClass");
1766    env->DeleteLocalRef(clazz);
1767
1768    return jniRegisterNativeMethods(env, "android/webkit/WebViewClassic", gJavaWebViewMethods, NELEM(gJavaWebViewMethods));
1769}
1770
1771} // namespace android
1772