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