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