• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "DumpLayer.h"
36 #include "Frame.h"
37 #include "GLWebViewState.h"
38 #include "GraphicsJNI.h"
39 #include "HTMLInputElement.h"
40 #include "IntPoint.h"
41 #include "IntRect.h"
42 #include "LayerAndroid.h"
43 #include "LayerContent.h"
44 #include "Node.h"
45 #include "utils/Functor.h"
46 #include "private/hwui/DrawGlInfo.h"
47 #include "PlatformGraphicsContext.h"
48 #include "PlatformString.h"
49 #include "ScrollableLayerAndroid.h"
50 #include "SelectText.h"
51 #include "SkCanvas.h"
52 #include "SkDumpCanvas.h"
53 #include "SkPicture.h"
54 #include "SkRect.h"
55 #include "SkTime.h"
56 #include "TilesManager.h"
57 #include "TransferQueue.h"
58 #include "WebCoreJni.h"
59 #include "WebRequestContext.h"
60 #include "WebViewCore.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 
86 namespace android {
87 
88 static jfieldID gWebViewField;
89 
90 //-------------------------------------
91 
GetJMethod(JNIEnv * env,jclass clazz,const char name[],const char signature[])92 static 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.
102 class WebView
103 {
104 public:
105 enum FrameCachePermission {
106     DontAllowNewer,
107     AllowNewer
108 };
109 
110 #define DRAW_EXTRAS_SIZE 2
111 enum DrawExtras { // keep this in sync with WebView.java
112     DrawExtrasNone = 0,
113     DrawExtrasSelection = 1,
114     DrawExtrasCursorRing = 2
115 };
116 
117 struct 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;
objectandroid::WebView::JavaGlue135     AutoJObject object(JNIEnv* env) {
136         return getRealObject(env, m_obj);
137     }
138 } m_javaGlue;
139 
WebView(JNIEnv * env,jobject javaWebView,int viewImpl,WTF::String drawableDir,bool isHighEndGfx)140 WebView(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 
~WebView()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 
getDrawExtra(DrawExtras extras)208 DrawExtra* getDrawExtra(DrawExtras extras)
209 {
210     if (extras == DrawExtrasNone)
211         return 0;
212     return m_extras[extras - 1];
213 }
214 
stopGL()215 void stopGL()
216 {
217 #if USE(ACCELERATED_COMPOSITING)
218     delete m_glWebViewState;
219     m_glWebViewState = 0;
220 #endif
221 }
222 
getWebViewCore() const223 WebViewCore* getWebViewCore() const {
224     return m_viewImpl;
225 }
226 
scrollRectOnScreen(const IntRect & rect)227 void 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 
drawGL(WebCore::IntRect & invScreenRect,WebCore::IntRect * invalRect,WebCore::IntRect & screenRect,int titleBarHeight,WebCore::IntRect & screenClip,float scale,int extras,bool shouldDraw)254 int 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 
draw(SkCanvas * canvas,SkColor bgColor,DrawExtras extras)299 void 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->updatePositionsRecursive(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 
getScaledMaxXScroll()330 int 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 
getScaledMaxYScroll()342 int 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.
updateRectsForGL()360 void 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)
findScrollableLayer(const LayerAndroid * parent,int x,int y,SkIRect * foundBounds)371 static 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 
scrollableLayer(int x,int y,SkIRect * layerRect,SkIRect * bounds)402 int 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 
scrollLayer(int layerId,int x,int y)416 void scrollLayer(int layerId, int x, int y)
417 {
418     if (m_glWebViewState)
419         m_glWebViewState->scrollLayer(layerId, x, y);
420 }
421 
setHeightCanMeasure(bool measure)422 void setHeightCanMeasure(bool measure)
423 {
424     m_heightCanMeasure = measure;
425 }
426 
getSelection()427 String getSelection()
428 {
429     SelectText* select = static_cast<SelectText*>(
430             getDrawExtra(WebView::DrawExtrasSelection));
431     if (select)
432         return select->getText();
433     return String();
434 }
435 
scrollBy(int dx,int dy)436 bool 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 
setIsScrolling(bool isScrolling)449 void setIsScrolling(bool isScrolling)
450 {
451 #if USE(ACCELERATED_COMPOSITING)
452     if (m_glWebViewState)
453         m_glWebViewState->setIsScrolling(isScrolling);
454 #endif
455 }
456 
viewInvalidate()457 void 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 
viewInvalidateRect(int l,int t,int r,int b)467 void 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 
postInvalidateDelayed(int64_t delay,const WebCore::IntRect & bounds)477 void 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)
copyScrollPosition(const LayerAndroid * fromRoot,LayerAndroid * toRoot,int layerId)489 static void copyScrollPosition(const LayerAndroid* fromRoot,
490                                LayerAndroid* toRoot, int layerId)
491 {
492     if (!fromRoot || !toRoot)
493         return;
494     const LayerAndroid* from = fromRoot->findById(layerId);
495     LayerAndroid* to = toRoot->findById(layerId);
496     if (!from || !to || !from->contentIsScrollable() || !to->contentIsScrollable())
497         return;
498     // TODO: Support this for iframes.
499     if (to->isIFrameContent() || from->isIFrameContent())
500         return;
501     to->setScrollOffset(from->getScrollOffset());
502 }
503 #endif
504 
getBaseLayer() const505 BaseLayerAndroid* getBaseLayer() const { return m_baseLayer; }
506 
setBaseLayer(BaseLayerAndroid * newBaseLayer,bool showVisualIndicator,bool isPictureAfterFirstLayout,int scrollingLayer)507 bool setBaseLayer(BaseLayerAndroid* newBaseLayer, bool showVisualIndicator,
508                   bool isPictureAfterFirstLayout, int scrollingLayer)
509 {
510     bool queueFull = false;
511 #if USE(ACCELERATED_COMPOSITING)
512     if (m_glWebViewState)
513         queueFull = m_glWebViewState->setBaseLayer(newBaseLayer, showVisualIndicator,
514                                                    isPictureAfterFirstLayout);
515 #endif
516 
517 #if ENABLE(ANDROID_OVERFLOW_SCROLL)
518     copyScrollPosition(m_baseLayer, newBaseLayer, scrollingLayer);
519 #endif
520     SkSafeUnref(m_baseLayer);
521     m_baseLayer = newBaseLayer;
522 
523     return queueFull;
524 }
525 
copyBaseContentToPicture(SkPicture * picture)526 void copyBaseContentToPicture(SkPicture* picture)
527 {
528     if (!m_baseLayer || !m_baseLayer->content())
529         return;
530     LayerContent* content = m_baseLayer->content();
531     SkCanvas* canvas = picture->beginRecording(content->width(), content->height(),
532                                               SkPicture::kUsePathBoundsForClip_RecordingFlag);
533 
534     // clear the BaseLayerAndroid's previous matrix (set at each draw)
535     SkMatrix baseMatrix;
536     baseMatrix.reset();
537     m_baseLayer->setMatrix(baseMatrix);
538 
539     m_baseLayer->draw(canvas, 0);
540 
541     picture->endRecording();
542 }
543 
hasContent()544 bool hasContent() {
545     if (!m_baseLayer || !m_baseLayer->content())
546         return false;
547     return !m_baseLayer->content()->isEmpty();
548 }
549 
setFunctor(Functor * functor)550 void setFunctor(Functor* functor) {
551     delete m_glDrawFunctor;
552     m_glDrawFunctor = functor;
553 }
554 
getFunctor()555 Functor* getFunctor() {
556     return m_glDrawFunctor;
557 }
558 
setVisibleContentRect(SkRect & visibleContentRect)559 void setVisibleContentRect(SkRect& visibleContentRect) {
560     m_visibleContentRect = visibleContentRect;
561 }
562 
setDrawExtra(DrawExtra * extra,DrawExtras type)563 void setDrawExtra(DrawExtra *extra, DrawExtras type)
564 {
565     if (type == DrawExtrasNone)
566         return;
567     DrawExtra* old = m_extras[type - 1];
568     m_extras[type - 1] = extra;
569     if (old != extra) {
570         delete old;
571     }
572 }
573 
setTextSelection(SelectText * selection)574 void setTextSelection(SelectText *selection) {
575     setDrawExtra(selection, DrawExtrasSelection);
576 }
577 
getLayerTransform(int layerId)578 const TransformationMatrix* getLayerTransform(int layerId) {
579     if (layerId != -1 && m_baseLayer) {
580         LayerAndroid* layer = m_baseLayer->findById(layerId);
581         // We need to make sure the drawTransform is up to date as this is
582         // called before a draw() or drawGL()
583         if (layer) {
584             m_baseLayer->updatePositionsRecursive(m_visibleContentRect);
585             return layer->drawTransform();
586         }
587     }
588     return 0;
589 }
590 
getHandleLayerId(SelectText::HandleId handleId,SkIPoint & cursorPoint,FloatQuad & textBounds)591 int getHandleLayerId(SelectText::HandleId handleId, SkIPoint& cursorPoint,
592         FloatQuad& textBounds) {
593     SelectText* selectText = static_cast<SelectText*>(getDrawExtra(DrawExtrasSelection));
594     if (!selectText || !m_baseLayer)
595         return -1;
596     int layerId = selectText->caretLayerId(handleId);
597     IntRect cursorRect = selectText->caretRect(handleId);
598     IntRect textRect = selectText->textRect(handleId);
599     // Rects exclude the last pixel on right/bottom. We want only included pixels.
600     cursorPoint.set(cursorRect.x(), cursorRect.maxY() - 1);
601     textRect.setHeight(std::max(1, textRect.height() - 1));
602     textRect.setWidth(std::max(1, textRect.width() - 1));
603     textBounds = FloatQuad(textRect);
604 
605     const TransformationMatrix* transform = getLayerTransform(layerId);
606     if (transform) {
607         // We're overloading the concept of Rect to be just the two
608         // points (bottom-left and top-right.
609         cursorPoint = transform->mapPoint(cursorPoint);
610         textBounds = transform->mapQuad(textBounds);
611     }
612     return layerId;
613 }
614 
mapLayerRect(int layerId,SkIRect & rect)615 void mapLayerRect(int layerId, SkIRect& rect) {
616     const TransformationMatrix* transform = getLayerTransform(layerId);
617     if (transform)
618         rect = transform->mapRect(rect);
619 }
620 
floatQuadToQuadF(JNIEnv * env,const FloatQuad & nativeTextQuad,jobject textQuad)621 void floatQuadToQuadF(JNIEnv* env, const FloatQuad& nativeTextQuad,
622         jobject textQuad)
623 {
624     jobject p1 = env->GetObjectField(textQuad, m_javaGlue.m_quadFP1);
625     jobject p2 = env->GetObjectField(textQuad, m_javaGlue.m_quadFP2);
626     jobject p3 = env->GetObjectField(textQuad, m_javaGlue.m_quadFP3);
627     jobject p4 = env->GetObjectField(textQuad, m_javaGlue.m_quadFP4);
628     GraphicsJNI::point_to_jpointf(nativeTextQuad.p1(), env, p1);
629     GraphicsJNI::point_to_jpointf(nativeTextQuad.p2(), env, p2);
630     GraphicsJNI::point_to_jpointf(nativeTextQuad.p3(), env, p3);
631     GraphicsJNI::point_to_jpointf(nativeTextQuad.p4(), env, p4);
632     env->DeleteLocalRef(p1);
633     env->DeleteLocalRef(p2);
634     env->DeleteLocalRef(p3);
635     env->DeleteLocalRef(p4);
636 }
637 
638 // This is called when WebView switches rendering modes in a more permanent fashion
639 // such as when the layer type is set or the view is attached/detached from the window
setHwAccelerated(bool hwAccelerated)640 int setHwAccelerated(bool hwAccelerated) {
641     if (!m_glWebViewState)
642         return 0;
643     LayerAndroid* root = m_baseLayer;
644     if (root)
645         return root->setHwAccelerated(hwAccelerated);
646     return 0;
647 }
648 
setDrawingPaused(bool isPaused)649 void setDrawingPaused(bool isPaused)
650 {
651     m_isDrawingPaused = isPaused;
652     if (m_viewImpl)
653         m_viewImpl->setPrerenderingEnabled(!isPaused);
654 }
655 
656 // Finds the rectangles within world to the left, right, top, and bottom
657 // of rect and adds them to rects. If no intersection exists, false is returned.
findMaskedRects(const FloatRect & world,const FloatRect & rect,Vector<FloatRect> & rects)658 static bool findMaskedRects(const FloatRect& world,
659         const FloatRect& rect, Vector<FloatRect>& rects) {
660     if (!world.intersects(rect))
661         return false; // nothing to subtract
662 
663     // left rectangle
664     if (rect.x() > world.x())
665         rects.append(FloatRect(world.x(), world.y(),
666                 rect.x() - world.x(), world.height()));
667     // top rectangle
668     if (rect.y() > world.y())
669         rects.append(FloatRect(world.x(), world.y(),
670                 world.width(), rect.y() - world.y()));
671     // right rectangle
672     if (rect.maxX() < world.maxX())
673         rects.append(FloatRect(rect.maxX(), world.y(),
674                 world.maxX() - rect.maxX(), world.height()));
675     // bottom rectangle
676     if (rect.maxY() < world.maxY())
677         rects.append(FloatRect(world.x(), rect.maxY(),
678                 world.width(), world.maxY() - rect.maxY()));
679     return true;
680 }
681 
682 // Returns false if layerId is a fixed position layer, otherwise
683 // all fixed position layer rectangles are subtracted from those within
684 // rects. Rects will be modified to contain rectangles that don't include
685 // the fixed position layer rectangles.
findMaskedRectsForLayer(LayerAndroid * layer,Vector<FloatRect> & rects,int layerId)686 static bool findMaskedRectsForLayer(LayerAndroid* layer,
687         Vector<FloatRect>& rects, int layerId)
688 {
689     if (layer->isPositionFixed()) {
690         if (layerId == layer->uniqueId())
691             return false;
692         FloatRect layerRect = layer->fullContentAreaMapped();
693         for (int i = rects.size() - 1; i >= 0; i--)
694             if (findMaskedRects(rects[i], layerRect, rects))
695                 rects.remove(i);
696     }
697 
698     int childIndex = 0;
699     while (LayerAndroid* child = layer->getChild(childIndex++))
700         if (!findMaskedRectsForLayer(child, rects, layerId))
701             return false;
702 
703     return true;
704 }
705 
706 // Finds the largest rectangle not masked by any fixed layer.
findMaxVisibleRect(int movingLayerId,SkIRect & visibleContentRect)707 void findMaxVisibleRect(int movingLayerId, SkIRect& visibleContentRect)
708 {
709     if (!m_baseLayer)
710         return;
711 
712     FloatRect visibleContentFloatRect(visibleContentRect);
713     m_baseLayer->updatePositionsRecursive(visibleContentFloatRect);
714     Vector<FloatRect> rects;
715     rects.append(visibleContentFloatRect);
716     if (findMaskedRectsForLayer(m_baseLayer, rects, movingLayerId)) {
717         float maxSize = 0.0;
718         const FloatRect* largest = 0;
719         for (unsigned int i = 0; i < rects.size(); i++) {
720             const FloatRect& rect = rects[i];
721             float size = rect.width() * rect.height();
722             if (size > maxSize) {
723                 maxSize = size;
724                 largest = &rect;
725             }
726         }
727         if (largest) {
728             SkRect largeRect = *largest;
729             largeRect.round(&visibleContentRect);
730         }
731     }
732 }
733 
isHandleLeft(SelectText::HandleId handleId)734 bool isHandleLeft(SelectText::HandleId handleId)
735 {
736     SelectText* selectText = static_cast<SelectText*>(getDrawExtra(DrawExtrasSelection));
737     if (!selectText)
738         return (handleId == SelectText::BaseHandle);
739 
740     return (selectText->getHandleType(handleId) == SelectText::LeftHandle);
741 }
742 
isPointVisible(int layerId,int contentX,int contentY)743 bool isPointVisible(int layerId, int contentX, int contentY)
744 {
745     bool isVisible = true;
746     const TransformationMatrix* transform = getLayerTransform(layerId);
747     if (transform) {
748         // layer is guaranteed to be non-NULL because of getLayerTransform
749         LayerAndroid* layer = m_baseLayer->findById(layerId);
750         IntRect rect = layer->visibleContentArea();
751         rect = transform->mapRect(rect);
752         isVisible = rect.contains(contentX, contentY);
753     }
754     return isVisible;
755 }
756 
757 private: // local state for WebView
758     bool m_isDrawingPaused;
759     // private to getFrameCache(); other functions operate in a different thread
760     WebViewCore* m_viewImpl;
761     int m_generation; // associate unique ID with sent kit focus to match with ui
762     // Corresponds to the same-named boolean on the java side.
763     bool m_heightCanMeasure;
764     int m_lastDx;
765     SkMSec m_lastDxTime;
766     DrawExtra* m_extras[DRAW_EXTRAS_SIZE];
767     BaseLayerAndroid* m_baseLayer;
768     Functor* m_glDrawFunctor;
769 #if USE(ACCELERATED_COMPOSITING)
770     GLWebViewState* m_glWebViewState;
771 #endif
772     SkRect m_visibleContentRect;
773     bool m_isHighEndGfx;
774 }; // end of WebView class
775 
776 
777 /**
778  * This class holds a function pointer and parameters for calling drawGL into a specific
779  * viewport. The pointer to the Functor will be put on a framework display list to be called
780  * when the display list is replayed.
781  */
782 class GLDrawFunctor : Functor {
783     public:
GLDrawFunctor(WebView * _wvInstance,int (WebView::* _funcPtr)(WebCore::IntRect &,WebCore::IntRect *,WebCore::IntRect &,int,WebCore::IntRect &,jfloat,jint,bool),WebCore::IntRect _invScreenRect,float _scale,int _extras)784     GLDrawFunctor(WebView* _wvInstance,
785             int (WebView::*_funcPtr)(WebCore::IntRect&, WebCore::IntRect*,
786                     WebCore::IntRect&, int, WebCore::IntRect&, jfloat, jint, bool),
787             WebCore::IntRect _invScreenRect, float _scale, int _extras) {
788         wvInstance = _wvInstance;
789         funcPtr = _funcPtr;
790         invScreenRect = _invScreenRect;
791         scale = _scale;
792         extras = _extras;
793     };
794 
operator ()(int messageId,void * data)795     status_t operator()(int messageId, void* data) {
796         TRACE_METHOD();
797         bool shouldDraw = (messageId == uirenderer::DrawGlInfo::kModeDraw);
798         if (shouldDraw)
799             wvInstance->updateRectsForGL();
800 
801         if (invScreenRect.isEmpty()) {
802             // NOOP operation if viewport is empty
803             return 0;
804         }
805 
806         WebCore::IntRect inval;
807         int titlebarHeight = screenRect.height() - invScreenRect.height();
808 
809         uirenderer::DrawGlInfo* info = reinterpret_cast<uirenderer::DrawGlInfo*>(data);
810         WebCore::IntRect screenClip(info->clipLeft, info->clipTop,
811                                     info->clipRight - info->clipLeft,
812                                     info->clipBottom - info->clipTop);
813 
814         WebCore::IntRect localInvScreenRect = invScreenRect;
815         if (info->isLayer) {
816             // When webview is on a layer, we need to use the viewport relative
817             // to the FBO, rather than the screen(which will use invScreenRect).
818             localInvScreenRect.setX(screenClip.x());
819             localInvScreenRect.setY(info->height - screenClip.y() - screenClip.height());
820         }
821         // Send the necessary info to the shader.
822         TilesManager::instance()->shader()->setGLDrawInfo(info);
823 
824         int returnFlags = (*wvInstance.*funcPtr)(localInvScreenRect, &inval, screenRect,
825                 titlebarHeight, screenClip, scale, extras, shouldDraw);
826         if ((returnFlags & uirenderer::DrawGlInfo::kStatusDraw) != 0) {
827             IntRect finalInval;
828             if (inval.isEmpty())
829                 finalInval = screenRect;
830             else {
831                 finalInval.setX(screenRect.x() + inval.x());
832                 finalInval.setY(screenRect.y() + titlebarHeight + inval.y());
833                 finalInval.setWidth(inval.width());
834                 finalInval.setHeight(inval.height());
835             }
836             info->dirtyLeft = finalInval.x();
837             info->dirtyTop = finalInval.y();
838             info->dirtyRight = finalInval.maxX();
839             info->dirtyBottom = finalInval.maxY();
840         }
841         // return 1 if invalidation needed, 2 to request non-drawing functor callback, 0 otherwise
842         ALOGV("returnFlags are %d, shouldDraw %d", returnFlags, shouldDraw);
843         return returnFlags;
844     }
updateScreenRect(WebCore::IntRect & _screenRect)845     void updateScreenRect(WebCore::IntRect& _screenRect) {
846         screenRect = _screenRect;
847     }
updateInvScreenRect(WebCore::IntRect & _invScreenRect)848     void updateInvScreenRect(WebCore::IntRect& _invScreenRect) {
849         invScreenRect = _invScreenRect;
850     }
updateScale(float _scale)851     void updateScale(float _scale) {
852         scale = _scale;
853     }
updateExtras(jint _extras)854     void updateExtras(jint _extras) {
855         extras = _extras;
856     }
857     private:
858     WebView* wvInstance;
859     int (WebView::*funcPtr)(WebCore::IntRect&, WebCore::IntRect*,
860             WebCore::IntRect&, int, WebCore::IntRect&, float, int, bool);
861     WebCore::IntRect invScreenRect;
862     WebCore::IntRect screenRect;
863     jfloat scale;
864     jint extras;
865 };
866 
867 /*
868  * Native JNI methods
869  */
870 
nativeCreate(JNIEnv * env,jobject obj,int viewImpl,jstring drawableDir,jboolean isHighEndGfx)871 static void nativeCreate(JNIEnv *env, jobject obj, int viewImpl,
872                          jstring drawableDir, jboolean isHighEndGfx)
873 {
874     WTF::String dir = jstringToWtfString(env, drawableDir);
875     new WebView(env, obj, viewImpl, dir, isHighEndGfx);
876     // NEED THIS OR SOMETHING LIKE IT!
877     //Release(obj);
878 }
879 
jrect_to_webrect(JNIEnv * env,jobject obj)880 static WebCore::IntRect jrect_to_webrect(JNIEnv* env, jobject obj)
881 {
882     if (obj) {
883         int L, T, R, B;
884         GraphicsJNI::get_jrect(env, obj, &L, &T, &R, &B);
885         return WebCore::IntRect(L, T, R - L, B - T);
886     } else
887         return WebCore::IntRect();
888 }
889 
jrectf_to_rect(JNIEnv * env,jobject obj)890 static SkRect jrectf_to_rect(JNIEnv* env, jobject obj)
891 {
892     SkRect rect = SkRect::MakeEmpty();
893     if (obj)
894         GraphicsJNI::jrectf_to_rect(env, obj, &rect);
895     return rect;
896 }
897 
nativeDraw(JNIEnv * env,jobject obj,jobject canv,jobject visible,jint color,jint extras)898 static void nativeDraw(JNIEnv *env, jobject obj, jobject canv,
899         jobject visible, jint color,
900         jint extras) {
901     SkCanvas* canvas = GraphicsJNI::getNativeCanvas(env, canv);
902     WebView* webView = GET_NATIVE_VIEW(env, obj);
903     SkRect visibleContentRect = jrectf_to_rect(env, visible);
904     webView->setVisibleContentRect(visibleContentRect);
905     webView->draw(canvas, color, static_cast<WebView::DrawExtras>(extras));
906 }
907 
nativeCreateDrawGLFunction(JNIEnv * env,jobject obj,jint nativeView,jobject jinvscreenrect,jobject jscreenrect,jobject jvisiblecontentrect,jfloat scale,jint extras)908 static jint nativeCreateDrawGLFunction(JNIEnv *env, jobject obj, jint nativeView,
909                                        jobject jinvscreenrect, jobject jscreenrect,
910                                        jobject jvisiblecontentrect,
911                                        jfloat scale, jint extras) {
912     WebCore::IntRect invScreenRect = jrect_to_webrect(env, jinvscreenrect);
913     WebView *wvInstance = reinterpret_cast<WebView*>(nativeView);
914     SkRect visibleContentRect = jrectf_to_rect(env, jvisiblecontentrect);
915     wvInstance->setVisibleContentRect(visibleContentRect);
916 
917     GLDrawFunctor* functor = (GLDrawFunctor*) wvInstance->getFunctor();
918     if (!functor) {
919         functor = new GLDrawFunctor(wvInstance, &android::WebView::drawGL,
920                                     invScreenRect, scale, extras);
921         wvInstance->setFunctor((Functor*) functor);
922     } else {
923         functor->updateInvScreenRect(invScreenRect);
924         functor->updateScale(scale);
925         functor->updateExtras(extras);
926     }
927 
928     WebCore::IntRect rect = jrect_to_webrect(env, jscreenrect);
929     functor->updateScreenRect(rect);
930 
931     return (jint)functor;
932 }
933 
nativeGetDrawGLFunction(JNIEnv * env,jobject obj,jint nativeView)934 static jint nativeGetDrawGLFunction(JNIEnv *env, jobject obj, jint nativeView) {
935     WebView *wvInstance = reinterpret_cast<WebView*>(nativeView);
936     if (!wvInstance)
937         return 0;
938 
939     return (jint) wvInstance->getFunctor();
940 }
941 
nativeUpdateDrawGLFunction(JNIEnv * env,jobject obj,jint nativeView,jobject jinvscreenrect,jobject jscreenrect,jobject jvisiblecontentrect,jfloat scale)942 static void nativeUpdateDrawGLFunction(JNIEnv *env, jobject obj, jint nativeView,
943                                        jobject jinvscreenrect, jobject jscreenrect,
944                                        jobject jvisiblecontentrect, jfloat scale) {
945     WebView *wvInstance = reinterpret_cast<WebView*>(nativeView);
946     if (wvInstance) {
947         GLDrawFunctor* functor = (GLDrawFunctor*) wvInstance->getFunctor();
948         if (functor) {
949             WebCore::IntRect invScreenRect = jrect_to_webrect(env, jinvscreenrect);
950             functor->updateInvScreenRect(invScreenRect);
951 
952             SkRect visibleContentRect = jrectf_to_rect(env, jvisiblecontentrect);
953             wvInstance->setVisibleContentRect(visibleContentRect);
954 
955             WebCore::IntRect screenRect = jrect_to_webrect(env, jscreenrect);
956             functor->updateScreenRect(screenRect);
957 
958             functor->updateScale(scale);
959         }
960     }
961 }
962 
nativeEvaluateLayersAnimations(JNIEnv * env,jobject obj,jint nativeView)963 static bool nativeEvaluateLayersAnimations(JNIEnv *env, jobject obj, jint nativeView)
964 {
965     // only call in software rendering, initialize and evaluate animations
966 #if USE(ACCELERATED_COMPOSITING)
967     BaseLayerAndroid* baseLayer = reinterpret_cast<WebView*>(nativeView)->getBaseLayer();
968     if (baseLayer) {
969         baseLayer->initAnimations();
970         return baseLayer->evaluateAnimations();
971     }
972 #endif
973     return false;
974 }
975 
nativeSetBaseLayer(JNIEnv * env,jobject obj,jint nativeView,jint layer,jboolean showVisualIndicator,jboolean isPictureAfterFirstLayout,jint scrollingLayer)976 static bool nativeSetBaseLayer(JNIEnv *env, jobject obj, jint nativeView, jint layer,
977                                jboolean showVisualIndicator,
978                                jboolean isPictureAfterFirstLayout,
979                                jint scrollingLayer)
980 {
981     BaseLayerAndroid* layerImpl = reinterpret_cast<BaseLayerAndroid*>(layer);
982     return reinterpret_cast<WebView*>(nativeView)->setBaseLayer(layerImpl, showVisualIndicator,
983                                                                 isPictureAfterFirstLayout,
984                                                                 scrollingLayer);
985 }
986 
nativeGetBaseLayer(JNIEnv * env,jobject obj,jint nativeView)987 static BaseLayerAndroid* nativeGetBaseLayer(JNIEnv *env, jobject obj, jint nativeView)
988 {
989     return reinterpret_cast<WebView*>(nativeView)->getBaseLayer();
990 }
991 
nativeCopyBaseContentToPicture(JNIEnv * env,jobject obj,jobject pict)992 static void nativeCopyBaseContentToPicture(JNIEnv *env, jobject obj, jobject pict)
993 {
994     SkPicture* picture = GraphicsJNI::getNativePicture(env, pict);
995     GET_NATIVE_VIEW(env, obj)->copyBaseContentToPicture(picture);
996 }
997 
nativeDumpLayerContentToPicture(JNIEnv * env,jobject obj,jint instance,jstring jclassName,jint layerId,jobject pict)998 static jboolean nativeDumpLayerContentToPicture(JNIEnv *env, jobject obj, jint instance,
999                                                 jstring jclassName, jint layerId, jobject pict)
1000 {
1001     bool success = false;
1002     SkPicture* picture = GraphicsJNI::getNativePicture(env, pict);
1003     std::string classname = jstringToStdString(env, jclassName);
1004     BaseLayerAndroid* baseLayer = reinterpret_cast<WebView*>(instance)->getBaseLayer();
1005     LayerAndroid* layer = baseLayer->findById(layerId);
1006     SkSafeRef(layer);
1007     if (layer && layer->subclassName() == classname) {
1008         LayerContent* content = layer->content();
1009         if (content) {
1010             SkCanvas* canvas = picture->beginRecording(content->width(), content->height());
1011             content->draw(canvas);
1012             picture->endRecording();
1013             success = true;
1014         }
1015     }
1016     SkSafeUnref(layer);
1017     return success;
1018 }
1019 
nativeHasContent(JNIEnv * env,jobject obj)1020 static bool nativeHasContent(JNIEnv *env, jobject obj)
1021 {
1022     return GET_NATIVE_VIEW(env, obj)->hasContent();
1023 }
1024 
nativeSetHeightCanMeasure(JNIEnv * env,jobject obj,bool measure)1025 static void nativeSetHeightCanMeasure(JNIEnv *env, jobject obj, bool measure)
1026 {
1027     WebView* view = GET_NATIVE_VIEW(env, obj);
1028     ALOG_ASSERT(view, "view not set in nativeSetHeightCanMeasure");
1029     view->setHeightCanMeasure(measure);
1030 }
1031 
nativeDestroy(JNIEnv * env,jobject obj,jint ptr)1032 static void nativeDestroy(JNIEnv *env, jobject obj, jint ptr)
1033 {
1034     WebView* view = reinterpret_cast<WebView*>(ptr);
1035     ALOGD("nativeDestroy view: %p", view);
1036     ALOG_ASSERT(view, "view not set in nativeDestroy");
1037     delete view;
1038 }
1039 
nativeStopGL(JNIEnv * env,jobject obj,jint ptr)1040 static void nativeStopGL(JNIEnv *env, jobject obj, jint ptr)
1041 {
1042     if (ptr)
1043         reinterpret_cast<WebView*>(ptr)->stopGL();
1044 }
1045 
nativeGetSelection(JNIEnv * env,jobject obj)1046 static jobject nativeGetSelection(JNIEnv *env, jobject obj)
1047 {
1048     WebView* view = GET_NATIVE_VIEW(env, obj);
1049     ALOG_ASSERT(view, "view not set in %s", __FUNCTION__);
1050     String selection = view->getSelection();
1051     return wtfStringToJstring(env, selection);
1052 }
1053 
nativeDiscardAllTextures(JNIEnv * env,jobject obj)1054 static void nativeDiscardAllTextures(JNIEnv *env, jobject obj)
1055 {
1056     //discard all textures for debugging/test purposes, but not gl backing memory
1057     bool allTextures = true, deleteGLTextures = false;
1058     TilesManager::instance()->discardTextures(allTextures, deleteGLTextures);
1059 }
1060 
nativeTileProfilingStart(JNIEnv * env,jobject obj)1061 static void nativeTileProfilingStart(JNIEnv *env, jobject obj)
1062 {
1063     TilesManager::instance()->getProfiler()->start();
1064 }
1065 
nativeTileProfilingStop(JNIEnv * env,jobject obj)1066 static float nativeTileProfilingStop(JNIEnv *env, jobject obj)
1067 {
1068     return TilesManager::instance()->getProfiler()->stop();
1069 }
1070 
nativeTileProfilingClear(JNIEnv * env,jobject obj)1071 static void nativeTileProfilingClear(JNIEnv *env, jobject obj)
1072 {
1073     TilesManager::instance()->getProfiler()->clear();
1074 }
1075 
nativeTileProfilingNumFrames(JNIEnv * env,jobject obj)1076 static int nativeTileProfilingNumFrames(JNIEnv *env, jobject obj)
1077 {
1078     return TilesManager::instance()->getProfiler()->numFrames();
1079 }
1080 
nativeTileProfilingNumTilesInFrame(JNIEnv * env,jobject obj,int frame)1081 static int nativeTileProfilingNumTilesInFrame(JNIEnv *env, jobject obj, int frame)
1082 {
1083     return TilesManager::instance()->getProfiler()->numTilesInFrame(frame);
1084 }
1085 
nativeTileProfilingGetInt(JNIEnv * env,jobject obj,int frame,int tile,jstring jkey)1086 static int nativeTileProfilingGetInt(JNIEnv *env, jobject obj, int frame, int tile, jstring jkey)
1087 {
1088     WTF::String key = jstringToWtfString(env, jkey);
1089     TileProfileRecord* record = TilesManager::instance()->getProfiler()->getTile(frame, tile);
1090 
1091     if (key == "left")
1092         return record->left;
1093     if (key == "top")
1094         return record->top;
1095     if (key == "right")
1096         return record->right;
1097     if (key == "bottom")
1098         return record->bottom;
1099     if (key == "level")
1100         return record->level;
1101     if (key == "isReady")
1102         return record->isReady ? 1 : 0;
1103     return -1;
1104 }
1105 
nativeTileProfilingGetFloat(JNIEnv * env,jobject obj,int frame,int tile,jstring jkey)1106 static float nativeTileProfilingGetFloat(JNIEnv *env, jobject obj, int frame, int tile, jstring jkey)
1107 {
1108     TileProfileRecord* record = TilesManager::instance()->getProfiler()->getTile(frame, tile);
1109     return record->scale;
1110 }
1111 
1112 #ifdef ANDROID_DUMP_DISPLAY_TREE
dumpToFile(const char text[],void * file)1113 static void dumpToFile(const char text[], void* file) {
1114     fwrite(text, 1, strlen(text), reinterpret_cast<FILE*>(file));
1115     fwrite("\n", 1, 1, reinterpret_cast<FILE*>(file));
1116 }
1117 #endif
1118 
1119 // Return true to view invalidate WebView
nativeSetProperty(JNIEnv * env,jobject obj,jstring jkey,jstring jvalue)1120 static bool nativeSetProperty(JNIEnv *env, jobject obj, jstring jkey, jstring jvalue)
1121 {
1122     WTF::String key = jstringToWtfString(env, jkey);
1123     WTF::String value = jstringToWtfString(env, jvalue);
1124     if (key == "inverted") {
1125         bool shouldInvert = (value == "true");
1126         TilesManager::instance()->setInvertedScreen(shouldInvert);
1127         return true;
1128     }
1129     else if (key == "inverted_contrast") {
1130         float contrast = value.toFloat();
1131         TilesManager::instance()->setInvertedScreenContrast(contrast);
1132         return true;
1133     }
1134     else if (key == "enable_cpu_upload_path") {
1135         TilesManager::instance()->transferQueue()->setTextureUploadType(
1136             value == "true" ? CpuUpload : GpuUpload);
1137     }
1138     else if (key == "use_minimal_memory") {
1139         TilesManager::instance()->setUseMinimalMemory(value == "true");
1140     }
1141     else if (key == "use_double_buffering") {
1142         TilesManager::instance()->setUseDoubleBuffering(value == "true");
1143     }
1144     else if (key == "tree_updates") {
1145         TilesManager::instance()->clearContentUpdates();
1146     }
1147     return false;
1148 }
1149 
nativeGetProperty(JNIEnv * env,jobject obj,jstring jkey)1150 static jstring nativeGetProperty(JNIEnv *env, jobject obj, jstring jkey)
1151 {
1152     WTF::String key = jstringToWtfString(env, jkey);
1153     if (key == "tree_updates") {
1154         int updates = TilesManager::instance()->getContentUpdates();
1155         WTF::String wtfUpdates = WTF::String::number(updates);
1156         return wtfStringToJstring(env, wtfUpdates);
1157     }
1158     return 0;
1159 }
1160 
nativeOnTrimMemory(JNIEnv * env,jobject obj,jint level)1161 static void nativeOnTrimMemory(JNIEnv *env, jobject obj, jint level)
1162 {
1163     if (TilesManager::hardwareAccelerationEnabled()) {
1164         // When we got TRIM_MEMORY_MODERATE or TRIM_MEMORY_COMPLETE, we should
1165         // make sure the transfer queue is empty and then abandon the Surface
1166         // Texture to avoid ANR b/c framework may destroy the EGL context.
1167         // Refer to WindowManagerImpl.java for conditions we followed.
1168         TilesManager* tilesManager = TilesManager::instance();
1169         if ((level >= TRIM_MEMORY_MODERATE
1170             && !tilesManager->highEndGfx())
1171             || level >= TRIM_MEMORY_COMPLETE) {
1172             ALOGD("OnTrimMemory with EGL Context %p", eglGetCurrentContext());
1173             tilesManager->cleanupGLResources();
1174         }
1175 
1176         bool freeAllTextures = (level > TRIM_MEMORY_UI_HIDDEN), glTextures = true;
1177         tilesManager->discardTextures(freeAllTextures, glTextures);
1178     }
1179 }
1180 
nativeDumpDisplayTree(JNIEnv * env,jobject jwebview,jstring jurl)1181 static void nativeDumpDisplayTree(JNIEnv* env, jobject jwebview, jstring jurl)
1182 {
1183 #ifdef ANDROID_DUMP_DISPLAY_TREE
1184     WebView* view = GET_NATIVE_VIEW(env, jwebview);
1185     ALOG_ASSERT(view, "view not set in %s", __FUNCTION__);
1186 
1187     if (view && view->getWebViewCore()) {
1188         FILE* file = fopen(DISPLAY_TREE_LOG_FILE, "w");
1189         if (file) {
1190             SkFormatDumper dumper(dumpToFile, file);
1191             // dump the URL
1192             if (jurl) {
1193                 const char* str = env->GetStringUTFChars(jurl, 0);
1194                 SkDebugf("Dumping %s to %s\n", str, DISPLAY_TREE_LOG_FILE);
1195                 dumpToFile(str, file);
1196                 env->ReleaseStringUTFChars(jurl, str);
1197             }
1198             // now dump the display tree
1199             SkDumpCanvas canvas(&dumper);
1200             // this will playback the picture into the canvas, which will
1201             // spew its contents to the dumper
1202             view->draw(&canvas, 0, WebView::DrawExtrasNone);
1203             // we're done with the file now
1204             fwrite("\n", 1, 1, file);
1205             fclose(file);
1206         }
1207 #if USE(ACCELERATED_COMPOSITING)
1208         const LayerAndroid* baseLayer = view->getBaseLayer();
1209         if (baseLayer) {
1210           FILE* file = fopen(LAYERS_TREE_LOG_FILE,"w");
1211           if (file) {
1212               WebCore::FileLayerDumper dumper(file);
1213               baseLayer->dumpLayers(&dumper);
1214               fclose(file);
1215           }
1216         }
1217 #endif
1218     }
1219 #endif
1220 }
1221 
nativeScrollableLayer(JNIEnv * env,jobject jwebview,jint nativeView,jint x,jint y,jobject rect,jobject bounds)1222 static int nativeScrollableLayer(JNIEnv* env, jobject jwebview, jint nativeView,
1223     jint x, jint y, jobject rect, jobject bounds)
1224 {
1225     WebView* webview = reinterpret_cast<WebView*>(nativeView);
1226     ALOG_ASSERT(webview, "webview not set in %s", __FUNCTION__);
1227     SkIRect nativeRect, nativeBounds;
1228     int id = webview->scrollableLayer(x, y, &nativeRect, &nativeBounds);
1229     if (rect)
1230         GraphicsJNI::irect_to_jrect(nativeRect, env, rect);
1231     if (bounds)
1232         GraphicsJNI::irect_to_jrect(nativeBounds, env, bounds);
1233     return id;
1234 }
1235 
nativeScrollLayer(JNIEnv * env,jobject obj,jint nativeView,jint layerId,jint x,jint y)1236 static bool nativeScrollLayer(JNIEnv* env, jobject obj,
1237     jint nativeView, jint layerId, jint x, jint y)
1238 {
1239 #if ENABLE(ANDROID_OVERFLOW_SCROLL)
1240     WebView* webview = reinterpret_cast<WebView*>(nativeView);
1241     webview->scrollLayer(layerId, x, y);
1242 
1243     //TODO: the below only needed for the SW rendering path
1244     LayerAndroid* baseLayer = webview->getBaseLayer();
1245     if (!baseLayer)
1246         return false;
1247     LayerAndroid* layer = baseLayer->findById(layerId);
1248     if (!layer || !layer->contentIsScrollable())
1249         return false;
1250     return static_cast<ScrollableLayerAndroid*>(layer)->scrollTo(x, y);
1251 #endif
1252     return false;
1253 }
1254 
nativeSetIsScrolling(JNIEnv * env,jobject jwebview,jboolean isScrolling)1255 static void nativeSetIsScrolling(JNIEnv* env, jobject jwebview, jboolean isScrolling)
1256 {
1257     // TODO: Pass in the native pointer instead
1258     WebView* view = GET_NATIVE_VIEW(env, jwebview);
1259     if (view)
1260         view->setIsScrolling(isScrolling);
1261 }
1262 
nativeUseHardwareAccelSkia(JNIEnv *,jobject,jboolean enabled)1263 static void nativeUseHardwareAccelSkia(JNIEnv*, jobject, jboolean enabled)
1264 {
1265     BaseRenderer::setCurrentRendererType(enabled ? BaseRenderer::Ganesh : BaseRenderer::Raster);
1266 }
1267 
nativeGetBackgroundColor(JNIEnv * env,jobject obj,jint nativeView)1268 static int nativeGetBackgroundColor(JNIEnv* env, jobject obj, jint nativeView)
1269 {
1270     WebView* view = reinterpret_cast<WebView*>(nativeView);
1271     BaseLayerAndroid* baseLayer = view->getBaseLayer();
1272     if (baseLayer) {
1273         WebCore::Color color = baseLayer->getBackgroundColor();
1274         if (color.isValid())
1275             return SkColorSetARGB(color.alpha(), color.red(),
1276                                   color.green(), color.blue());
1277     }
1278     return SK_ColorWHITE;
1279 }
1280 
nativeSetPauseDrawing(JNIEnv * env,jobject obj,jint nativeView,jboolean pause)1281 static void nativeSetPauseDrawing(JNIEnv *env, jobject obj, jint nativeView,
1282                                       jboolean pause)
1283 {
1284     reinterpret_cast<WebView*>(nativeView)->setDrawingPaused(pause);
1285 }
1286 
nativeSetTextSelection(JNIEnv * env,jobject obj,jint nativeView,jint selectionPtr)1287 static void nativeSetTextSelection(JNIEnv *env, jobject obj, jint nativeView,
1288                                    jint selectionPtr)
1289 {
1290     SelectText* selection = reinterpret_cast<SelectText*>(selectionPtr);
1291     reinterpret_cast<WebView*>(nativeView)->setTextSelection(selection);
1292 }
1293 
nativeGetHandleLayerId(JNIEnv * env,jobject obj,jint nativeView,jint handleIndex,jobject cursorPoint,jobject textQuad)1294 static jint nativeGetHandleLayerId(JNIEnv *env, jobject obj, jint nativeView,
1295                                      jint handleIndex, jobject cursorPoint,
1296                                      jobject textQuad)
1297 {
1298     WebView* webview = reinterpret_cast<WebView*>(nativeView);
1299     SkIPoint nativePoint;
1300     FloatQuad nativeTextQuad;
1301     int layerId = webview->getHandleLayerId((SelectText::HandleId) handleIndex,
1302             nativePoint, nativeTextQuad);
1303     if (cursorPoint)
1304         GraphicsJNI::ipoint_to_jpoint(nativePoint, env, cursorPoint);
1305     if (textQuad)
1306         webview->floatQuadToQuadF(env, nativeTextQuad, textQuad);
1307     return layerId;
1308 }
1309 
nativeMapLayerRect(JNIEnv * env,jobject obj,jint nativeView,jint layerId,jobject rect)1310 static void nativeMapLayerRect(JNIEnv *env, jobject obj, jint nativeView,
1311         jint layerId, jobject rect)
1312 {
1313     WebView* webview = reinterpret_cast<WebView*>(nativeView);
1314     SkIRect nativeRect;
1315     GraphicsJNI::jrect_to_irect(env, rect, &nativeRect);
1316     webview->mapLayerRect(layerId, nativeRect);
1317     GraphicsJNI::irect_to_jrect(nativeRect, env, rect);
1318 }
1319 
nativeSetHwAccelerated(JNIEnv * env,jobject obj,jint nativeView,jboolean hwAccelerated)1320 static jint nativeSetHwAccelerated(JNIEnv *env, jobject obj, jint nativeView,
1321         jboolean hwAccelerated)
1322 {
1323     WebView* webview = reinterpret_cast<WebView*>(nativeView);
1324     return webview->setHwAccelerated(hwAccelerated);
1325 }
1326 
nativeFindMaxVisibleRect(JNIEnv * env,jobject obj,jint nativeView,jint movingLayerId,jobject visibleContentRect)1327 static void nativeFindMaxVisibleRect(JNIEnv *env, jobject obj, jint nativeView,
1328         jint movingLayerId, jobject visibleContentRect)
1329 {
1330     WebView* webview = reinterpret_cast<WebView*>(nativeView);
1331     SkIRect nativeRect;
1332     GraphicsJNI::jrect_to_irect(env, visibleContentRect, &nativeRect);
1333     webview->findMaxVisibleRect(movingLayerId, nativeRect);
1334     GraphicsJNI::irect_to_jrect(nativeRect, env, visibleContentRect);
1335 }
1336 
nativeIsHandleLeft(JNIEnv * env,jobject obj,jint nativeView,jint handleId)1337 static bool nativeIsHandleLeft(JNIEnv *env, jobject obj, jint nativeView,
1338         jint handleId)
1339 {
1340     WebView* webview = reinterpret_cast<WebView*>(nativeView);
1341     return webview->isHandleLeft(static_cast<SelectText::HandleId>(handleId));
1342 }
1343 
nativeIsPointVisible(JNIEnv * env,jobject obj,jint nativeView,jint layerId,jint contentX,jint contentY)1344 static bool nativeIsPointVisible(JNIEnv *env, jobject obj, jint nativeView,
1345         jint layerId, jint contentX, jint contentY)
1346 {
1347     WebView* webview = reinterpret_cast<WebView*>(nativeView);
1348     return webview->isPointVisible(layerId, contentX, contentY);
1349 }
1350 
1351 /*
1352  * JNI registration
1353  */
1354 static JNINativeMethod gJavaWebViewMethods[] = {
1355     { "nativeCreate", "(ILjava/lang/String;Z)V",
1356         (void*) nativeCreate },
1357     { "nativeDestroy", "(I)V",
1358         (void*) nativeDestroy },
1359     { "nativeDraw", "(Landroid/graphics/Canvas;Landroid/graphics/RectF;II)V",
1360         (void*) nativeDraw },
1361     { "nativeCreateDrawGLFunction", "(ILandroid/graphics/Rect;Landroid/graphics/Rect;Landroid/graphics/RectF;FI)I",
1362         (void*) nativeCreateDrawGLFunction },
1363     { "nativeGetDrawGLFunction", "(I)I",
1364         (void*) nativeGetDrawGLFunction },
1365     { "nativeUpdateDrawGLFunction", "(ILandroid/graphics/Rect;Landroid/graphics/Rect;Landroid/graphics/RectF;F)V",
1366         (void*) nativeUpdateDrawGLFunction },
1367     { "nativeDumpDisplayTree", "(Ljava/lang/String;)V",
1368         (void*) nativeDumpDisplayTree },
1369     { "nativeEvaluateLayersAnimations", "(I)Z",
1370         (void*) nativeEvaluateLayersAnimations },
1371     { "nativeGetSelection", "()Ljava/lang/String;",
1372         (void*) nativeGetSelection },
1373     { "nativeSetHeightCanMeasure", "(Z)V",
1374         (void*) nativeSetHeightCanMeasure },
1375     { "nativeSetBaseLayer", "(IIZZI)Z",
1376         (void*) nativeSetBaseLayer },
1377     { "nativeGetBaseLayer", "(I)I",
1378         (void*) nativeGetBaseLayer },
1379     { "nativeCopyBaseContentToPicture", "(Landroid/graphics/Picture;)V",
1380         (void*) nativeCopyBaseContentToPicture },
1381     { "nativeDumpLayerContentToPicture", "(ILjava/lang/String;ILandroid/graphics/Picture;)Z",
1382         (void*) nativeDumpLayerContentToPicture },
1383     { "nativeHasContent", "()Z",
1384         (void*) nativeHasContent },
1385     { "nativeDiscardAllTextures", "()V",
1386         (void*) nativeDiscardAllTextures },
1387     { "nativeTileProfilingStart", "()V",
1388         (void*) nativeTileProfilingStart },
1389     { "nativeTileProfilingStop", "()F",
1390         (void*) nativeTileProfilingStop },
1391     { "nativeTileProfilingClear", "()V",
1392         (void*) nativeTileProfilingClear },
1393     { "nativeTileProfilingNumFrames", "()I",
1394         (void*) nativeTileProfilingNumFrames },
1395     { "nativeTileProfilingNumTilesInFrame", "(I)I",
1396         (void*) nativeTileProfilingNumTilesInFrame },
1397     { "nativeTileProfilingGetInt", "(IILjava/lang/String;)I",
1398         (void*) nativeTileProfilingGetInt },
1399     { "nativeTileProfilingGetFloat", "(IILjava/lang/String;)F",
1400         (void*) nativeTileProfilingGetFloat },
1401     { "nativeStopGL", "(I)V",
1402         (void*) nativeStopGL },
1403     { "nativeScrollableLayer", "(IIILandroid/graphics/Rect;Landroid/graphics/Rect;)I",
1404         (void*) nativeScrollableLayer },
1405     { "nativeScrollLayer", "(IIII)Z",
1406         (void*) nativeScrollLayer },
1407     { "nativeSetIsScrolling", "(Z)V",
1408         (void*) nativeSetIsScrolling },
1409     { "nativeUseHardwareAccelSkia", "(Z)V",
1410         (void*) nativeUseHardwareAccelSkia },
1411     { "nativeGetBackgroundColor", "(I)I",
1412         (void*) nativeGetBackgroundColor },
1413     { "nativeSetProperty", "(Ljava/lang/String;Ljava/lang/String;)Z",
1414         (void*) nativeSetProperty },
1415     { "nativeGetProperty", "(Ljava/lang/String;)Ljava/lang/String;",
1416         (void*) nativeGetProperty },
1417     { "nativeOnTrimMemory", "(I)V",
1418         (void*) nativeOnTrimMemory },
1419     { "nativeSetPauseDrawing", "(IZ)V",
1420         (void*) nativeSetPauseDrawing },
1421     { "nativeSetTextSelection", "(II)V",
1422         (void*) nativeSetTextSelection },
1423     { "nativeGetHandleLayerId", "(IILandroid/graphics/Point;Landroid/webkit/QuadF;)I",
1424         (void*) nativeGetHandleLayerId },
1425     { "nativeMapLayerRect", "(IILandroid/graphics/Rect;)V",
1426         (void*) nativeMapLayerRect },
1427     { "nativeSetHwAccelerated", "(IZ)I",
1428         (void*) nativeSetHwAccelerated },
1429     { "nativeFindMaxVisibleRect", "(IILandroid/graphics/Rect;)V",
1430         (void*) nativeFindMaxVisibleRect },
1431     { "nativeIsHandleLeft", "(II)Z",
1432         (void*) nativeIsHandleLeft },
1433     { "nativeIsPointVisible", "(IIII)Z",
1434         (void*) nativeIsPointVisible },
1435 };
1436 
registerWebView(JNIEnv * env)1437 int registerWebView(JNIEnv* env)
1438 {
1439     jclass clazz = env->FindClass("android/webkit/WebViewClassic");
1440     ALOG_ASSERT(clazz, "Unable to find class android/webkit/WebViewClassic");
1441     gWebViewField = env->GetFieldID(clazz, "mNativeClass", "I");
1442     ALOG_ASSERT(gWebViewField, "Unable to find android/webkit/WebViewClassic.mNativeClass");
1443     env->DeleteLocalRef(clazz);
1444 
1445     return jniRegisterNativeMethods(env, "android/webkit/WebViewClassic", gJavaWebViewMethods, NELEM(gJavaWebViewMethods));
1446 }
1447 
1448 } // namespace android
1449