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
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 (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 = ▭
725 }
726 }
727 if (largest) {
728 SkRect largeRect = *largest;
729 largeRect.round(&visibleContentRect);
730 }
731 }
732 }
733
734 private: // local state for WebView
735 bool m_isDrawingPaused;
736 // private to getFrameCache(); other functions operate in a different thread
737 WebViewCore* m_viewImpl;
738 int m_generation; // associate unique ID with sent kit focus to match with ui
739 // Corresponds to the same-named boolean on the java side.
740 bool m_heightCanMeasure;
741 int m_lastDx;
742 SkMSec m_lastDxTime;
743 DrawExtra* m_extras[DRAW_EXTRAS_SIZE];
744 BaseLayerAndroid* m_baseLayer;
745 Functor* m_glDrawFunctor;
746 #if USE(ACCELERATED_COMPOSITING)
747 GLWebViewState* m_glWebViewState;
748 #endif
749 SkRect m_visibleContentRect;
750 bool m_isHighEndGfx;
751 }; // end of WebView class
752
753
754 /**
755 * This class holds a function pointer and parameters for calling drawGL into a specific
756 * viewport. The pointer to the Functor will be put on a framework display list to be called
757 * when the display list is replayed.
758 */
759 class GLDrawFunctor : Functor {
760 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)761 GLDrawFunctor(WebView* _wvInstance,
762 int (WebView::*_funcPtr)(WebCore::IntRect&, WebCore::IntRect*,
763 WebCore::IntRect&, int, WebCore::IntRect&, jfloat, jint, bool),
764 WebCore::IntRect _invScreenRect, float _scale, int _extras) {
765 wvInstance = _wvInstance;
766 funcPtr = _funcPtr;
767 invScreenRect = _invScreenRect;
768 scale = _scale;
769 extras = _extras;
770 };
771
operator ()(int messageId,void * data)772 status_t operator()(int messageId, void* data) {
773 TRACE_METHOD();
774 bool shouldDraw = (messageId == uirenderer::DrawGlInfo::kModeDraw);
775 if (shouldDraw)
776 wvInstance->updateRectsForGL();
777
778 if (invScreenRect.isEmpty()) {
779 // NOOP operation if viewport is empty
780 return 0;
781 }
782
783 WebCore::IntRect inval;
784 int titlebarHeight = screenRect.height() - invScreenRect.height();
785
786 uirenderer::DrawGlInfo* info = reinterpret_cast<uirenderer::DrawGlInfo*>(data);
787 WebCore::IntRect screenClip(info->clipLeft, info->clipTop,
788 info->clipRight - info->clipLeft,
789 info->clipBottom - info->clipTop);
790
791 WebCore::IntRect localInvScreenRect = invScreenRect;
792 if (info->isLayer) {
793 // When webview is on a layer, we need to use the viewport relative
794 // to the FBO, rather than the screen(which will use invScreenRect).
795 localInvScreenRect.setX(screenClip.x());
796 localInvScreenRect.setY(info->height - screenClip.y() - screenClip.height());
797 }
798 // Send the necessary info to the shader.
799 TilesManager::instance()->shader()->setGLDrawInfo(info);
800
801 int returnFlags = (*wvInstance.*funcPtr)(localInvScreenRect, &inval, screenRect,
802 titlebarHeight, screenClip, scale, extras, shouldDraw);
803 if ((returnFlags & uirenderer::DrawGlInfo::kStatusDraw) != 0) {
804 IntRect finalInval;
805 if (inval.isEmpty())
806 finalInval = screenRect;
807 else {
808 finalInval.setX(screenRect.x() + inval.x());
809 finalInval.setY(screenRect.y() + titlebarHeight + inval.y());
810 finalInval.setWidth(inval.width());
811 finalInval.setHeight(inval.height());
812 }
813 info->dirtyLeft = finalInval.x();
814 info->dirtyTop = finalInval.y();
815 info->dirtyRight = finalInval.maxX();
816 info->dirtyBottom = finalInval.maxY();
817 }
818 // return 1 if invalidation needed, 2 to request non-drawing functor callback, 0 otherwise
819 ALOGV("returnFlags are %d, shouldDraw %d", returnFlags, shouldDraw);
820 return returnFlags;
821 }
updateScreenRect(WebCore::IntRect & _screenRect)822 void updateScreenRect(WebCore::IntRect& _screenRect) {
823 screenRect = _screenRect;
824 }
updateInvScreenRect(WebCore::IntRect & _invScreenRect)825 void updateInvScreenRect(WebCore::IntRect& _invScreenRect) {
826 invScreenRect = _invScreenRect;
827 }
updateScale(float _scale)828 void updateScale(float _scale) {
829 scale = _scale;
830 }
updateExtras(jint _extras)831 void updateExtras(jint _extras) {
832 extras = _extras;
833 }
834 private:
835 WebView* wvInstance;
836 int (WebView::*funcPtr)(WebCore::IntRect&, WebCore::IntRect*,
837 WebCore::IntRect&, int, WebCore::IntRect&, float, int, bool);
838 WebCore::IntRect invScreenRect;
839 WebCore::IntRect screenRect;
840 jfloat scale;
841 jint extras;
842 };
843
844 /*
845 * Native JNI methods
846 */
847
nativeCreate(JNIEnv * env,jobject obj,int viewImpl,jstring drawableDir,jboolean isHighEndGfx)848 static void nativeCreate(JNIEnv *env, jobject obj, int viewImpl,
849 jstring drawableDir, jboolean isHighEndGfx)
850 {
851 WTF::String dir = jstringToWtfString(env, drawableDir);
852 new WebView(env, obj, viewImpl, dir, isHighEndGfx);
853 // NEED THIS OR SOMETHING LIKE IT!
854 //Release(obj);
855 }
856
jrect_to_webrect(JNIEnv * env,jobject obj)857 static WebCore::IntRect jrect_to_webrect(JNIEnv* env, jobject obj)
858 {
859 if (obj) {
860 int L, T, R, B;
861 GraphicsJNI::get_jrect(env, obj, &L, &T, &R, &B);
862 return WebCore::IntRect(L, T, R - L, B - T);
863 } else
864 return WebCore::IntRect();
865 }
866
jrectf_to_rect(JNIEnv * env,jobject obj)867 static SkRect jrectf_to_rect(JNIEnv* env, jobject obj)
868 {
869 SkRect rect = SkRect::MakeEmpty();
870 if (obj)
871 GraphicsJNI::jrectf_to_rect(env, obj, &rect);
872 return rect;
873 }
874
nativeDraw(JNIEnv * env,jobject obj,jobject canv,jobject visible,jint color,jint extras)875 static void nativeDraw(JNIEnv *env, jobject obj, jobject canv,
876 jobject visible, jint color,
877 jint extras) {
878 SkCanvas* canvas = GraphicsJNI::getNativeCanvas(env, canv);
879 WebView* webView = GET_NATIVE_VIEW(env, obj);
880 SkRect visibleContentRect = jrectf_to_rect(env, visible);
881 webView->setVisibleContentRect(visibleContentRect);
882 webView->draw(canvas, color, static_cast<WebView::DrawExtras>(extras));
883 }
884
nativeCreateDrawGLFunction(JNIEnv * env,jobject obj,jint nativeView,jobject jinvscreenrect,jobject jscreenrect,jobject jvisiblecontentrect,jfloat scale,jint extras)885 static jint nativeCreateDrawGLFunction(JNIEnv *env, jobject obj, jint nativeView,
886 jobject jinvscreenrect, jobject jscreenrect,
887 jobject jvisiblecontentrect,
888 jfloat scale, jint extras) {
889 WebCore::IntRect invScreenRect = jrect_to_webrect(env, jinvscreenrect);
890 WebView *wvInstance = reinterpret_cast<WebView*>(nativeView);
891 SkRect visibleContentRect = jrectf_to_rect(env, jvisiblecontentrect);
892 wvInstance->setVisibleContentRect(visibleContentRect);
893
894 GLDrawFunctor* functor = (GLDrawFunctor*) wvInstance->getFunctor();
895 if (!functor) {
896 functor = new GLDrawFunctor(wvInstance, &android::WebView::drawGL,
897 invScreenRect, scale, extras);
898 wvInstance->setFunctor((Functor*) functor);
899 } else {
900 functor->updateInvScreenRect(invScreenRect);
901 functor->updateScale(scale);
902 functor->updateExtras(extras);
903 }
904
905 WebCore::IntRect rect = jrect_to_webrect(env, jscreenrect);
906 functor->updateScreenRect(rect);
907
908 return (jint)functor;
909 }
910
nativeGetDrawGLFunction(JNIEnv * env,jobject obj,jint nativeView)911 static jint nativeGetDrawGLFunction(JNIEnv *env, jobject obj, jint nativeView) {
912 WebView *wvInstance = reinterpret_cast<WebView*>(nativeView);
913 if (!wvInstance)
914 return 0;
915
916 return (jint) wvInstance->getFunctor();
917 }
918
nativeUpdateDrawGLFunction(JNIEnv * env,jobject obj,jint nativeView,jobject jinvscreenrect,jobject jscreenrect,jobject jvisiblecontentrect,jfloat scale)919 static void nativeUpdateDrawGLFunction(JNIEnv *env, jobject obj, jint nativeView,
920 jobject jinvscreenrect, jobject jscreenrect,
921 jobject jvisiblecontentrect, jfloat scale) {
922 WebView *wvInstance = reinterpret_cast<WebView*>(nativeView);
923 if (wvInstance) {
924 GLDrawFunctor* functor = (GLDrawFunctor*) wvInstance->getFunctor();
925 if (functor) {
926 WebCore::IntRect invScreenRect = jrect_to_webrect(env, jinvscreenrect);
927 functor->updateInvScreenRect(invScreenRect);
928
929 SkRect visibleContentRect = jrectf_to_rect(env, jvisiblecontentrect);
930 wvInstance->setVisibleContentRect(visibleContentRect);
931
932 WebCore::IntRect screenRect = jrect_to_webrect(env, jscreenrect);
933 functor->updateScreenRect(screenRect);
934
935 functor->updateScale(scale);
936 }
937 }
938 }
939
nativeEvaluateLayersAnimations(JNIEnv * env,jobject obj,jint nativeView)940 static bool nativeEvaluateLayersAnimations(JNIEnv *env, jobject obj, jint nativeView)
941 {
942 // only call in software rendering, initialize and evaluate animations
943 #if USE(ACCELERATED_COMPOSITING)
944 BaseLayerAndroid* baseLayer = reinterpret_cast<WebView*>(nativeView)->getBaseLayer();
945 if (baseLayer) {
946 baseLayer->initAnimations();
947 return baseLayer->evaluateAnimations();
948 }
949 #endif
950 return false;
951 }
952
nativeSetBaseLayer(JNIEnv * env,jobject obj,jint nativeView,jint layer,jboolean showVisualIndicator,jboolean isPictureAfterFirstLayout,jint scrollingLayer)953 static bool nativeSetBaseLayer(JNIEnv *env, jobject obj, jint nativeView, jint layer,
954 jboolean showVisualIndicator,
955 jboolean isPictureAfterFirstLayout,
956 jint scrollingLayer)
957 {
958 BaseLayerAndroid* layerImpl = reinterpret_cast<BaseLayerAndroid*>(layer);
959 return reinterpret_cast<WebView*>(nativeView)->setBaseLayer(layerImpl, showVisualIndicator,
960 isPictureAfterFirstLayout,
961 scrollingLayer);
962 }
963
nativeGetBaseLayer(JNIEnv * env,jobject obj,jint nativeView)964 static BaseLayerAndroid* nativeGetBaseLayer(JNIEnv *env, jobject obj, jint nativeView)
965 {
966 return reinterpret_cast<WebView*>(nativeView)->getBaseLayer();
967 }
968
nativeCopyBaseContentToPicture(JNIEnv * env,jobject obj,jobject pict)969 static void nativeCopyBaseContentToPicture(JNIEnv *env, jobject obj, jobject pict)
970 {
971 SkPicture* picture = GraphicsJNI::getNativePicture(env, pict);
972 GET_NATIVE_VIEW(env, obj)->copyBaseContentToPicture(picture);
973 }
974
nativeHasContent(JNIEnv * env,jobject obj)975 static bool nativeHasContent(JNIEnv *env, jobject obj)
976 {
977 return GET_NATIVE_VIEW(env, obj)->hasContent();
978 }
979
nativeSetHeightCanMeasure(JNIEnv * env,jobject obj,bool measure)980 static void nativeSetHeightCanMeasure(JNIEnv *env, jobject obj, bool measure)
981 {
982 WebView* view = GET_NATIVE_VIEW(env, obj);
983 ALOG_ASSERT(view, "view not set in nativeSetHeightCanMeasure");
984 view->setHeightCanMeasure(measure);
985 }
986
nativeDestroy(JNIEnv * env,jobject obj,jint ptr)987 static void nativeDestroy(JNIEnv *env, jobject obj, jint ptr)
988 {
989 WebView* view = reinterpret_cast<WebView*>(ptr);
990 ALOGD("nativeDestroy view: %p", view);
991 ALOG_ASSERT(view, "view not set in nativeDestroy");
992 delete view;
993 }
994
nativeStopGL(JNIEnv * env,jobject obj,jint ptr)995 static void nativeStopGL(JNIEnv *env, jobject obj, jint ptr)
996 {
997 if (ptr)
998 reinterpret_cast<WebView*>(ptr)->stopGL();
999 }
1000
nativeGetSelection(JNIEnv * env,jobject obj)1001 static jobject nativeGetSelection(JNIEnv *env, jobject obj)
1002 {
1003 WebView* view = GET_NATIVE_VIEW(env, obj);
1004 ALOG_ASSERT(view, "view not set in %s", __FUNCTION__);
1005 String selection = view->getSelection();
1006 return wtfStringToJstring(env, selection);
1007 }
1008
nativeDiscardAllTextures(JNIEnv * env,jobject obj)1009 static void nativeDiscardAllTextures(JNIEnv *env, jobject obj)
1010 {
1011 //discard all textures for debugging/test purposes, but not gl backing memory
1012 bool allTextures = true, deleteGLTextures = false;
1013 TilesManager::instance()->discardTextures(allTextures, deleteGLTextures);
1014 }
1015
nativeTileProfilingStart(JNIEnv * env,jobject obj)1016 static void nativeTileProfilingStart(JNIEnv *env, jobject obj)
1017 {
1018 TilesManager::instance()->getProfiler()->start();
1019 }
1020
nativeTileProfilingStop(JNIEnv * env,jobject obj)1021 static float nativeTileProfilingStop(JNIEnv *env, jobject obj)
1022 {
1023 return TilesManager::instance()->getProfiler()->stop();
1024 }
1025
nativeTileProfilingClear(JNIEnv * env,jobject obj)1026 static void nativeTileProfilingClear(JNIEnv *env, jobject obj)
1027 {
1028 TilesManager::instance()->getProfiler()->clear();
1029 }
1030
nativeTileProfilingNumFrames(JNIEnv * env,jobject obj)1031 static int nativeTileProfilingNumFrames(JNIEnv *env, jobject obj)
1032 {
1033 return TilesManager::instance()->getProfiler()->numFrames();
1034 }
1035
nativeTileProfilingNumTilesInFrame(JNIEnv * env,jobject obj,int frame)1036 static int nativeTileProfilingNumTilesInFrame(JNIEnv *env, jobject obj, int frame)
1037 {
1038 return TilesManager::instance()->getProfiler()->numTilesInFrame(frame);
1039 }
1040
nativeTileProfilingGetInt(JNIEnv * env,jobject obj,int frame,int tile,jstring jkey)1041 static int nativeTileProfilingGetInt(JNIEnv *env, jobject obj, int frame, int tile, jstring jkey)
1042 {
1043 WTF::String key = jstringToWtfString(env, jkey);
1044 TileProfileRecord* record = TilesManager::instance()->getProfiler()->getTile(frame, tile);
1045
1046 if (key == "left")
1047 return record->left;
1048 if (key == "top")
1049 return record->top;
1050 if (key == "right")
1051 return record->right;
1052 if (key == "bottom")
1053 return record->bottom;
1054 if (key == "level")
1055 return record->level;
1056 if (key == "isReady")
1057 return record->isReady ? 1 : 0;
1058 return -1;
1059 }
1060
nativeTileProfilingGetFloat(JNIEnv * env,jobject obj,int frame,int tile,jstring jkey)1061 static float nativeTileProfilingGetFloat(JNIEnv *env, jobject obj, int frame, int tile, jstring jkey)
1062 {
1063 TileProfileRecord* record = TilesManager::instance()->getProfiler()->getTile(frame, tile);
1064 return record->scale;
1065 }
1066
1067 #ifdef ANDROID_DUMP_DISPLAY_TREE
dumpToFile(const char text[],void * file)1068 static void dumpToFile(const char text[], void* file) {
1069 fwrite(text, 1, strlen(text), reinterpret_cast<FILE*>(file));
1070 fwrite("\n", 1, 1, reinterpret_cast<FILE*>(file));
1071 }
1072 #endif
1073
1074 // Return true to view invalidate WebView
nativeSetProperty(JNIEnv * env,jobject obj,jstring jkey,jstring jvalue)1075 static bool nativeSetProperty(JNIEnv *env, jobject obj, jstring jkey, jstring jvalue)
1076 {
1077 WTF::String key = jstringToWtfString(env, jkey);
1078 WTF::String value = jstringToWtfString(env, jvalue);
1079 if (key == "inverted") {
1080 bool shouldInvert = (value == "true");
1081 TilesManager::instance()->setInvertedScreen(shouldInvert);
1082 return true;
1083 }
1084 else if (key == "inverted_contrast") {
1085 float contrast = value.toFloat();
1086 TilesManager::instance()->setInvertedScreenContrast(contrast);
1087 return true;
1088 }
1089 else if (key == "enable_cpu_upload_path") {
1090 TilesManager::instance()->transferQueue()->setTextureUploadType(
1091 value == "true" ? CpuUpload : GpuUpload);
1092 }
1093 else if (key == "use_minimal_memory") {
1094 TilesManager::instance()->setUseMinimalMemory(value == "true");
1095 }
1096 else if (key == "use_double_buffering") {
1097 TilesManager::instance()->setUseDoubleBuffering(value == "true");
1098 }
1099 else if (key == "tree_updates") {
1100 TilesManager::instance()->clearContentUpdates();
1101 }
1102 return false;
1103 }
1104
nativeGetProperty(JNIEnv * env,jobject obj,jstring jkey)1105 static jstring nativeGetProperty(JNIEnv *env, jobject obj, jstring jkey)
1106 {
1107 WTF::String key = jstringToWtfString(env, jkey);
1108 if (key == "tree_updates") {
1109 int updates = TilesManager::instance()->getContentUpdates();
1110 WTF::String wtfUpdates = WTF::String::number(updates);
1111 return wtfStringToJstring(env, wtfUpdates);
1112 }
1113 return 0;
1114 }
1115
nativeOnTrimMemory(JNIEnv * env,jobject obj,jint level)1116 static void nativeOnTrimMemory(JNIEnv *env, jobject obj, jint level)
1117 {
1118 if (TilesManager::hardwareAccelerationEnabled()) {
1119 // When we got TRIM_MEMORY_MODERATE or TRIM_MEMORY_COMPLETE, we should
1120 // make sure the transfer queue is empty and then abandon the Surface
1121 // Texture to avoid ANR b/c framework may destroy the EGL context.
1122 // Refer to WindowManagerImpl.java for conditions we followed.
1123 TilesManager* tilesManager = TilesManager::instance();
1124 if ((level >= TRIM_MEMORY_MODERATE
1125 && !tilesManager->highEndGfx())
1126 || level >= TRIM_MEMORY_COMPLETE) {
1127 ALOGD("OnTrimMemory with EGL Context %p", eglGetCurrentContext());
1128 tilesManager->cleanupGLResources();
1129 }
1130
1131 bool freeAllTextures = (level > TRIM_MEMORY_UI_HIDDEN), glTextures = true;
1132 tilesManager->discardTextures(freeAllTextures, glTextures);
1133 }
1134 }
1135
nativeDumpDisplayTree(JNIEnv * env,jobject jwebview,jstring jurl)1136 static void nativeDumpDisplayTree(JNIEnv* env, jobject jwebview, jstring jurl)
1137 {
1138 #ifdef ANDROID_DUMP_DISPLAY_TREE
1139 WebView* view = GET_NATIVE_VIEW(env, jwebview);
1140 ALOG_ASSERT(view, "view not set in %s", __FUNCTION__);
1141
1142 if (view && view->getWebViewCore()) {
1143 FILE* file = fopen(DISPLAY_TREE_LOG_FILE, "w");
1144 if (file) {
1145 SkFormatDumper dumper(dumpToFile, file);
1146 // dump the URL
1147 if (jurl) {
1148 const char* str = env->GetStringUTFChars(jurl, 0);
1149 SkDebugf("Dumping %s to %s\n", str, DISPLAY_TREE_LOG_FILE);
1150 dumpToFile(str, file);
1151 env->ReleaseStringUTFChars(jurl, str);
1152 }
1153 // now dump the display tree
1154 SkDumpCanvas canvas(&dumper);
1155 // this will playback the picture into the canvas, which will
1156 // spew its contents to the dumper
1157 view->draw(&canvas, 0, WebView::DrawExtrasNone);
1158 // we're done with the file now
1159 fwrite("\n", 1, 1, file);
1160 fclose(file);
1161 }
1162 #if USE(ACCELERATED_COMPOSITING)
1163 const LayerAndroid* baseLayer = view->getBaseLayer();
1164 if (baseLayer) {
1165 FILE* file = fopen(LAYERS_TREE_LOG_FILE,"w");
1166 if (file) {
1167 baseLayer->dumpLayers(file, 0);
1168 fclose(file);
1169 }
1170 }
1171 #endif
1172 }
1173 #endif
1174 }
1175
nativeScrollableLayer(JNIEnv * env,jobject jwebview,jint nativeView,jint x,jint y,jobject rect,jobject bounds)1176 static int nativeScrollableLayer(JNIEnv* env, jobject jwebview, jint nativeView,
1177 jint x, jint y, jobject rect, jobject bounds)
1178 {
1179 WebView* webview = reinterpret_cast<WebView*>(nativeView);
1180 ALOG_ASSERT(webview, "webview not set in %s", __FUNCTION__);
1181 SkIRect nativeRect, nativeBounds;
1182 int id = webview->scrollableLayer(x, y, &nativeRect, &nativeBounds);
1183 if (rect)
1184 GraphicsJNI::irect_to_jrect(nativeRect, env, rect);
1185 if (bounds)
1186 GraphicsJNI::irect_to_jrect(nativeBounds, env, bounds);
1187 return id;
1188 }
1189
nativeScrollLayer(JNIEnv * env,jobject obj,jint nativeView,jint layerId,jint x,jint y)1190 static bool nativeScrollLayer(JNIEnv* env, jobject obj,
1191 jint nativeView, jint layerId, jint x, jint y)
1192 {
1193 #if ENABLE(ANDROID_OVERFLOW_SCROLL)
1194 WebView* webview = reinterpret_cast<WebView*>(nativeView);
1195 webview->scrollLayer(layerId, x, y);
1196
1197 //TODO: the below only needed for the SW rendering path
1198 LayerAndroid* baseLayer = webview->getBaseLayer();
1199 if (!baseLayer)
1200 return false;
1201 LayerAndroid* layer = baseLayer->findById(layerId);
1202 if (!layer || !layer->contentIsScrollable())
1203 return false;
1204 return static_cast<ScrollableLayerAndroid*>(layer)->scrollTo(x, y);
1205 #endif
1206 return false;
1207 }
1208
nativeSetIsScrolling(JNIEnv * env,jobject jwebview,jboolean isScrolling)1209 static void nativeSetIsScrolling(JNIEnv* env, jobject jwebview, jboolean isScrolling)
1210 {
1211 // TODO: Pass in the native pointer instead
1212 WebView* view = GET_NATIVE_VIEW(env, jwebview);
1213 if (view)
1214 view->setIsScrolling(isScrolling);
1215 }
1216
nativeUseHardwareAccelSkia(JNIEnv *,jobject,jboolean enabled)1217 static void nativeUseHardwareAccelSkia(JNIEnv*, jobject, jboolean enabled)
1218 {
1219 BaseRenderer::setCurrentRendererType(enabled ? BaseRenderer::Ganesh : BaseRenderer::Raster);
1220 }
1221
nativeGetBackgroundColor(JNIEnv * env,jobject obj,jint nativeView)1222 static int nativeGetBackgroundColor(JNIEnv* env, jobject obj, jint nativeView)
1223 {
1224 WebView* view = reinterpret_cast<WebView*>(nativeView);
1225 BaseLayerAndroid* baseLayer = view->getBaseLayer();
1226 if (baseLayer) {
1227 WebCore::Color color = baseLayer->getBackgroundColor();
1228 if (color.isValid())
1229 return SkColorSetARGB(color.alpha(), color.red(),
1230 color.green(), color.blue());
1231 }
1232 return SK_ColorWHITE;
1233 }
1234
nativeSetPauseDrawing(JNIEnv * env,jobject obj,jint nativeView,jboolean pause)1235 static void nativeSetPauseDrawing(JNIEnv *env, jobject obj, jint nativeView,
1236 jboolean pause)
1237 {
1238 reinterpret_cast<WebView*>(nativeView)->setDrawingPaused(pause);
1239 }
1240
nativeSetTextSelection(JNIEnv * env,jobject obj,jint nativeView,jint selectionPtr)1241 static void nativeSetTextSelection(JNIEnv *env, jobject obj, jint nativeView,
1242 jint selectionPtr)
1243 {
1244 SelectText* selection = reinterpret_cast<SelectText*>(selectionPtr);
1245 reinterpret_cast<WebView*>(nativeView)->setTextSelection(selection);
1246 }
1247
nativeGetHandleLayerId(JNIEnv * env,jobject obj,jint nativeView,jint handleIndex,jobject cursorPoint,jobject textQuad)1248 static jint nativeGetHandleLayerId(JNIEnv *env, jobject obj, jint nativeView,
1249 jint handleIndex, jobject cursorPoint,
1250 jobject textQuad)
1251 {
1252 WebView* webview = reinterpret_cast<WebView*>(nativeView);
1253 SkIPoint nativePoint;
1254 FloatQuad nativeTextQuad;
1255 int layerId = webview->getHandleLayerId((SelectText::HandleId) handleIndex,
1256 nativePoint, nativeTextQuad);
1257 if (cursorPoint)
1258 GraphicsJNI::ipoint_to_jpoint(nativePoint, env, cursorPoint);
1259 if (textQuad)
1260 webview->floatQuadToQuadF(env, nativeTextQuad, textQuad);
1261 return layerId;
1262 }
1263
nativeMapLayerRect(JNIEnv * env,jobject obj,jint nativeView,jint layerId,jobject rect)1264 static void nativeMapLayerRect(JNIEnv *env, jobject obj, jint nativeView,
1265 jint layerId, jobject rect)
1266 {
1267 WebView* webview = reinterpret_cast<WebView*>(nativeView);
1268 SkIRect nativeRect;
1269 GraphicsJNI::jrect_to_irect(env, rect, &nativeRect);
1270 webview->mapLayerRect(layerId, nativeRect);
1271 GraphicsJNI::irect_to_jrect(nativeRect, env, rect);
1272 }
1273
nativeSetHwAccelerated(JNIEnv * env,jobject obj,jint nativeView,jboolean hwAccelerated)1274 static jint nativeSetHwAccelerated(JNIEnv *env, jobject obj, jint nativeView,
1275 jboolean hwAccelerated)
1276 {
1277 WebView* webview = reinterpret_cast<WebView*>(nativeView);
1278 return webview->setHwAccelerated(hwAccelerated);
1279 }
1280
nativeFindMaxVisibleRect(JNIEnv * env,jobject obj,jint nativeView,jint movingLayerId,jobject visibleContentRect)1281 static void nativeFindMaxVisibleRect(JNIEnv *env, jobject obj, jint nativeView,
1282 jint movingLayerId, jobject visibleContentRect)
1283 {
1284 WebView* webview = reinterpret_cast<WebView*>(nativeView);
1285 SkIRect nativeRect;
1286 GraphicsJNI::jrect_to_irect(env, visibleContentRect, &nativeRect);
1287 webview->findMaxVisibleRect(movingLayerId, nativeRect);
1288 GraphicsJNI::irect_to_jrect(nativeRect, env, visibleContentRect);
1289 }
1290
1291 /*
1292 * JNI registration
1293 */
1294 static JNINativeMethod gJavaWebViewMethods[] = {
1295 { "nativeCreate", "(ILjava/lang/String;Z)V",
1296 (void*) nativeCreate },
1297 { "nativeDestroy", "(I)V",
1298 (void*) nativeDestroy },
1299 { "nativeDraw", "(Landroid/graphics/Canvas;Landroid/graphics/RectF;II)V",
1300 (void*) nativeDraw },
1301 { "nativeCreateDrawGLFunction", "(ILandroid/graphics/Rect;Landroid/graphics/Rect;Landroid/graphics/RectF;FI)I",
1302 (void*) nativeCreateDrawGLFunction },
1303 { "nativeGetDrawGLFunction", "(I)I",
1304 (void*) nativeGetDrawGLFunction },
1305 { "nativeUpdateDrawGLFunction", "(ILandroid/graphics/Rect;Landroid/graphics/Rect;Landroid/graphics/RectF;F)V",
1306 (void*) nativeUpdateDrawGLFunction },
1307 { "nativeDumpDisplayTree", "(Ljava/lang/String;)V",
1308 (void*) nativeDumpDisplayTree },
1309 { "nativeEvaluateLayersAnimations", "(I)Z",
1310 (void*) nativeEvaluateLayersAnimations },
1311 { "nativeGetSelection", "()Ljava/lang/String;",
1312 (void*) nativeGetSelection },
1313 { "nativeSetHeightCanMeasure", "(Z)V",
1314 (void*) nativeSetHeightCanMeasure },
1315 { "nativeSetBaseLayer", "(IIZZI)Z",
1316 (void*) nativeSetBaseLayer },
1317 { "nativeGetBaseLayer", "(I)I",
1318 (void*) nativeGetBaseLayer },
1319 { "nativeCopyBaseContentToPicture", "(Landroid/graphics/Picture;)V",
1320 (void*) nativeCopyBaseContentToPicture },
1321 { "nativeHasContent", "()Z",
1322 (void*) nativeHasContent },
1323 { "nativeDiscardAllTextures", "()V",
1324 (void*) nativeDiscardAllTextures },
1325 { "nativeTileProfilingStart", "()V",
1326 (void*) nativeTileProfilingStart },
1327 { "nativeTileProfilingStop", "()F",
1328 (void*) nativeTileProfilingStop },
1329 { "nativeTileProfilingClear", "()V",
1330 (void*) nativeTileProfilingClear },
1331 { "nativeTileProfilingNumFrames", "()I",
1332 (void*) nativeTileProfilingNumFrames },
1333 { "nativeTileProfilingNumTilesInFrame", "(I)I",
1334 (void*) nativeTileProfilingNumTilesInFrame },
1335 { "nativeTileProfilingGetInt", "(IILjava/lang/String;)I",
1336 (void*) nativeTileProfilingGetInt },
1337 { "nativeTileProfilingGetFloat", "(IILjava/lang/String;)F",
1338 (void*) nativeTileProfilingGetFloat },
1339 { "nativeStopGL", "(I)V",
1340 (void*) nativeStopGL },
1341 { "nativeScrollableLayer", "(IIILandroid/graphics/Rect;Landroid/graphics/Rect;)I",
1342 (void*) nativeScrollableLayer },
1343 { "nativeScrollLayer", "(IIII)Z",
1344 (void*) nativeScrollLayer },
1345 { "nativeSetIsScrolling", "(Z)V",
1346 (void*) nativeSetIsScrolling },
1347 { "nativeUseHardwareAccelSkia", "(Z)V",
1348 (void*) nativeUseHardwareAccelSkia },
1349 { "nativeGetBackgroundColor", "(I)I",
1350 (void*) nativeGetBackgroundColor },
1351 { "nativeSetProperty", "(Ljava/lang/String;Ljava/lang/String;)Z",
1352 (void*) nativeSetProperty },
1353 { "nativeGetProperty", "(Ljava/lang/String;)Ljava/lang/String;",
1354 (void*) nativeGetProperty },
1355 { "nativeOnTrimMemory", "(I)V",
1356 (void*) nativeOnTrimMemory },
1357 { "nativeSetPauseDrawing", "(IZ)V",
1358 (void*) nativeSetPauseDrawing },
1359 { "nativeSetTextSelection", "(II)V",
1360 (void*) nativeSetTextSelection },
1361 { "nativeGetHandleLayerId", "(IILandroid/graphics/Point;Landroid/webkit/QuadF;)I",
1362 (void*) nativeGetHandleLayerId },
1363 { "nativeMapLayerRect", "(IILandroid/graphics/Rect;)V",
1364 (void*) nativeMapLayerRect },
1365 { "nativeSetHwAccelerated", "(IZ)I",
1366 (void*) nativeSetHwAccelerated },
1367 { "nativeFindMaxVisibleRect", "(IILandroid/graphics/Rect;)V",
1368 (void*) nativeFindMaxVisibleRect },
1369 };
1370
registerWebView(JNIEnv * env)1371 int registerWebView(JNIEnv* env)
1372 {
1373 jclass clazz = env->FindClass("android/webkit/WebViewClassic");
1374 ALOG_ASSERT(clazz, "Unable to find class android/webkit/WebViewClassic");
1375 gWebViewField = env->GetFieldID(clazz, "mNativeClass", "I");
1376 ALOG_ASSERT(gWebViewField, "Unable to find android/webkit/WebViewClassic.mNativeClass");
1377 env->DeleteLocalRef(clazz);
1378
1379 return jniRegisterNativeMethods(env, "android/webkit/WebViewClassic", gJavaWebViewMethods, NELEM(gJavaWebViewMethods));
1380 }
1381
1382 } // namespace android
1383