1 /*
2 * Copyright 2008, 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 #include "config.h"
27 #include "PluginWidgetAndroid.h"
28
29 #if ENABLE(TOUCH_EVENTS)
30 #include "ChromeClient.h"
31 #endif
32 #include "Document.h"
33 #include "Element.h"
34 #include "Frame.h"
35 #include "Page.h"
36 #include "PluginPackage.h"
37 #include "PluginView.h"
38 #include "PluginWidgetAndroid.h"
39 #include "ScrollView.h"
40 #include "SkANP.h"
41 #include "SkFlipPixelRef.h"
42 #include "SkString.h"
43 #include "SkTime.h"
44 #include "WebViewCore.h"
45 #include "android_graphics.h"
46 #include <JNIUtility.h>
47
48 //#define PLUGIN_DEBUG_LOCAL // controls the printing of log messages
49 #define DEBUG_EVENTS 0 // logs event contents, return value, and processing time
50 #define DEBUG_VISIBLE_RECTS 0 // temporary debug printfs and fixes
51
52 #define MAX( a, b ) ( ((a) > (b)) ? (a) : (b) )
53
54 // this include statement must follow the declaration of PLUGIN_DEBUG_LOCAL
55 #include "PluginDebugAndroid.h"
56
PluginWidgetAndroid(WebCore::PluginView * view)57 PluginWidgetAndroid::PluginWidgetAndroid(WebCore::PluginView* view)
58 : m_pluginView(view) {
59 m_flipPixelRef = NULL;
60 m_core = NULL;
61 m_drawingModel = kBitmap_ANPDrawingModel;
62 m_eventFlags = 0;
63 m_pluginWindow = NULL;
64 m_requestedVisibleRectCount = 0;
65 m_requestedVisibleRect.setEmpty();
66 m_visibleDocRect.setEmpty();
67 m_pluginBounds.setEmpty();
68 m_hasFocus = false;
69 m_isFullScreen = false;
70 m_visible = false;
71 m_cachedZoomLevel = 0;
72 m_embeddedView = NULL;
73 m_embeddedViewAttached = false;
74 m_acceptEvents = false;
75 m_isSurfaceClippedOut = false;
76 m_layer = 0;
77 m_powerState = kDefault_ANPPowerState;
78 m_fullScreenOrientation = -1;
79 m_drawEventDelayed = false;
80 }
81
~PluginWidgetAndroid()82 PluginWidgetAndroid::~PluginWidgetAndroid() {
83 PLUGIN_LOG("%p Deleting Plugin", m_pluginView->instance());
84 m_acceptEvents = false;
85 if (m_core) {
86 setPowerState(kDefault_ANPPowerState);
87 m_core->removePlugin(this);
88 if (m_isFullScreen) {
89 exitFullScreen(true);
90 }
91 if (m_embeddedView) {
92 m_core->destroySurface(m_embeddedView);
93 }
94 }
95
96 // cleanup any remaining JNI References
97 JNIEnv* env = JSC::Bindings::getJNIEnv();
98 if (m_embeddedView) {
99 env->DeleteGlobalRef(m_embeddedView);
100 }
101
102 SkSafeUnref(m_flipPixelRef);
103 SkSafeUnref(m_layer);
104 }
105
init(android::WebViewCore * core)106 void PluginWidgetAndroid::init(android::WebViewCore* core) {
107 m_core = core;
108 m_core->addPlugin(this);
109 m_acceptEvents = true;
110 PLUGIN_LOG("%p Initialized Plugin", m_pluginView->instance());
111 }
112
computeConfig(bool isTransparent)113 static SkBitmap::Config computeConfig(bool isTransparent) {
114 return isTransparent ? SkBitmap::kARGB_8888_Config
115 : SkBitmap::kRGB_565_Config;
116 }
117
setWindow(NPWindow * window,bool isTransparent)118 void PluginWidgetAndroid::setWindow(NPWindow* window, bool isTransparent) {
119
120 // store the reference locally for easy lookup
121 m_pluginWindow = window;
122
123 // make a copy of the previous bounds
124 SkIRect oldPluginBounds = m_pluginBounds;
125
126 // keep a local copy of the plugin bounds because the m_pluginWindow pointer
127 // gets updated values prior to this method being called
128 m_pluginBounds.set(m_pluginWindow->x, m_pluginWindow->y,
129 m_pluginWindow->x + m_pluginWindow->width,
130 m_pluginWindow->y + m_pluginWindow->height);
131
132 PLUGIN_LOG("%p PluginBounds (%d,%d,%d,%d)", m_pluginView->instance(),
133 m_pluginBounds.fLeft, m_pluginBounds.fTop,
134 m_pluginBounds.fRight, m_pluginBounds.fBottom);
135
136 const bool boundsChanged = m_pluginBounds != oldPluginBounds;
137
138 //TODO hack to ensure that we grab the most recent screen dimensions and scale
139 ANPRectI screenCoords;
140 m_core->getVisibleScreen(screenCoords);
141 float scale = m_core->scale();
142 bool scaleChanged = m_cachedZoomLevel != scale;
143 setVisibleScreen(screenCoords, scale);
144
145 // if the scale changed then setVisibleScreen will call this function and
146 // this call will potentially fire a duplicate draw event
147 if (!scaleChanged) {
148 sendSizeAndVisibilityEvents(boundsChanged);
149 }
150 layoutSurface(boundsChanged);
151
152 if (m_drawingModel != kSurface_ANPDrawingModel) {
153 SkSafeUnref(m_flipPixelRef);
154 m_flipPixelRef = new SkFlipPixelRef(computeConfig(isTransparent),
155 window->width, window->height);
156 }
157 }
158
setDrawingModel(ANPDrawingModel model)159 bool PluginWidgetAndroid::setDrawingModel(ANPDrawingModel model) {
160
161 if (model == kOpenGL_ANPDrawingModel && m_layer == 0) {
162 jobject webview = m_core->getWebViewJavaObject();
163 m_layer = new WebCore::MediaLayer(webview);
164 }
165 else if (model != kOpenGL_ANPDrawingModel && m_layer != 0) {
166 m_layer->unref();
167 m_layer = 0;
168 }
169
170 if (m_drawingModel != model) {
171 // Trigger layer computation in RenderLayerCompositor
172 m_pluginView->getElement()->setNeedsStyleRecalc(SyntheticStyleChange);
173 }
174
175 m_drawingModel = model;
176 return true;
177 }
178
checkSurfaceReady()179 void PluginWidgetAndroid::checkSurfaceReady() {
180 if(!m_drawEventDelayed)
181 return;
182
183 m_drawEventDelayed = false;
184 sendSizeAndVisibilityEvents(true);
185 }
186
187 // returned rect is in the page coordinate
isDirty(SkIRect * rect) const188 bool PluginWidgetAndroid::isDirty(SkIRect* rect) const {
189 // nothing to report if we haven't had setWindow() called yet
190 if (NULL == m_flipPixelRef) {
191 return false;
192 }
193
194 const SkRegion& dirty = m_flipPixelRef->dirtyRgn();
195 if (dirty.isEmpty()) {
196 return false;
197 } else {
198 if (rect) {
199 *rect = dirty.getBounds();
200 rect->offset(m_pluginWindow->x, m_pluginWindow->y);
201 }
202 return true;
203 }
204 }
205
inval(const WebCore::IntRect & rect,bool signalRedraw)206 void PluginWidgetAndroid::inval(const WebCore::IntRect& rect,
207 bool signalRedraw) {
208 // nothing to do if we haven't had setWindow() called yet. m_flipPixelRef
209 // will also be null if this is a Surface model.
210 if (NULL == m_flipPixelRef) {
211 return;
212 }
213
214 m_flipPixelRef->inval(rect);
215
216 if (signalRedraw && m_flipPixelRef->isDirty()) {
217 m_core->invalPlugin(this);
218 }
219 }
220
viewInvalidate()221 void PluginWidgetAndroid::viewInvalidate() {
222 WebCore::IntRect rect(m_pluginBounds.fLeft, m_pluginBounds.fTop,
223 m_pluginBounds.width(), m_pluginBounds.height());
224 m_core->viewInvalidate(rect);
225 }
226
draw(SkCanvas * canvas)227 void PluginWidgetAndroid::draw(SkCanvas* canvas) {
228 if (NULL == m_flipPixelRef || !m_flipPixelRef->isDirty()) {
229 return;
230 }
231
232 SkAutoFlipUpdate update(m_flipPixelRef);
233 const SkBitmap& bitmap = update.bitmap();
234 const SkRegion& dirty = update.dirty();
235
236 ANPEvent event;
237 SkANP::InitEvent(&event, kDraw_ANPEventType);
238
239 event.data.draw.model = m_drawingModel;
240 SkANP::SetRect(&event.data.draw.clip, dirty.getBounds());
241
242 switch (m_drawingModel) {
243 case kBitmap_ANPDrawingModel: {
244 WebCore::PluginPackage* pkg = m_pluginView->plugin();
245 NPP instance = m_pluginView->instance();
246
247 if (SkANP::SetBitmap(&event.data.draw.data.bitmap,
248 bitmap) &&
249 pkg->pluginFuncs()->event(instance, &event)) {
250
251 if (canvas && m_pluginWindow) {
252 SkBitmap bm(bitmap);
253 bm.setPixelRef(m_flipPixelRef);
254 canvas->drawBitmap(bm, 0, 0);
255 }
256 }
257 break;
258 }
259 default:
260 break;
261 }
262 }
263
setSurfaceClip(const SkIRect & clip)264 void PluginWidgetAndroid::setSurfaceClip(const SkIRect& clip) {
265
266 if (m_drawingModel != kSurface_ANPDrawingModel)
267 return;
268
269 /* don't display surfaces that are either entirely clipped or only 1x1 in
270 size. It appears that when an element is absolutely positioned and has
271 been completely clipped in CSS that webkit still sends a clip of 1x1.
272 */
273 bool clippedOut = (clip.width() <= 1 && clip.height() <= 1);
274 if(clippedOut != m_isSurfaceClippedOut) {
275 m_isSurfaceClippedOut = clippedOut;
276 layoutSurface();
277 }
278 }
279
layoutSurface(bool pluginBoundsChanged)280 void PluginWidgetAndroid::layoutSurface(bool pluginBoundsChanged) {
281
282 if (m_drawingModel != kSurface_ANPDrawingModel)
283 return;
284 if (!m_pluginWindow)
285 return;
286
287
288 bool displayPlugin = m_pluginView->isVisible() && !m_isSurfaceClippedOut;
289 PLUGIN_LOG("%p DisplayPlugin[%d] visible=[%d] clipped=[%d]",
290 m_pluginView->instance(), displayPlugin,
291 m_pluginView->isVisible(), m_isSurfaceClippedOut);
292
293 // if the surface does not exist then create a new surface
294 if (!m_embeddedView && displayPlugin) {
295
296 WebCore::PluginPackage* pkg = m_pluginView->plugin();
297 NPP instance = m_pluginView->instance();
298
299 jobject pluginSurface;
300 pkg->pluginFuncs()->getvalue(instance, kJavaSurface_ANPGetValue,
301 static_cast<void*>(&pluginSurface));
302
303 jobject tempObj = m_core->addSurface(pluginSurface,
304 m_pluginWindow->x, m_pluginWindow->y,
305 m_pluginWindow->width, m_pluginWindow->height);
306
307 if (tempObj) {
308 JNIEnv* env = JSC::Bindings::getJNIEnv();
309 m_embeddedView = env->NewGlobalRef(tempObj);
310 m_embeddedViewAttached = true;
311 }
312 // if the view is unattached but visible then attach it
313 } else if (m_embeddedView && !m_embeddedViewAttached && displayPlugin && !m_isFullScreen) {
314 m_core->updateSurface(m_embeddedView, m_pluginWindow->x, m_pluginWindow->y,
315 m_pluginWindow->width, m_pluginWindow->height);
316 m_embeddedViewAttached = true;
317 // if the view is attached but invisible then remove it
318 } else if (m_embeddedView && m_embeddedViewAttached && !displayPlugin) {
319 m_core->destroySurface(m_embeddedView);
320 m_embeddedViewAttached = false;
321 // if the plugin's bounds have changed and it's visible then update it
322 } else if (pluginBoundsChanged && displayPlugin && !m_isFullScreen) {
323 m_core->updateSurface(m_embeddedView, m_pluginWindow->x, m_pluginWindow->y,
324 m_pluginWindow->width, m_pluginWindow->height);
325
326 }
327 }
328
sendEvent(const ANPEvent & evt)329 int16_t PluginWidgetAndroid::sendEvent(const ANPEvent& evt) {
330 if (!m_acceptEvents)
331 return 0;
332 WebCore::PluginPackage* pkg = m_pluginView->plugin();
333 NPP instance = m_pluginView->instance();
334 // "missing" plugins won't have these
335 if (pkg && instance) {
336
337 // if the plugin is gaining focus then update our state now to allow
338 // the plugin's event handler to perform actions that require focus
339 if (evt.eventType == kLifecycle_ANPEventType &&
340 evt.data.lifecycle.action == kGainFocus_ANPLifecycleAction) {
341 m_hasFocus = true;
342 }
343
344 #if DEBUG_EVENTS
345 SkMSec startTime = SkTime::GetMSecs();
346 #endif
347
348 // make a localCopy since the actual plugin may not respect its constness,
349 // and so we don't want our caller to have its param modified
350 ANPEvent localCopy = evt;
351 int16_t result = pkg->pluginFuncs()->event(instance, &localCopy);
352
353 #if DEBUG_EVENTS
354 SkMSec endTime = SkTime::GetMSecs();
355 PLUGIN_LOG_EVENT(instance, &evt, result, endTime - startTime);
356 #endif
357
358 // if the plugin is losing focus then delay the update of our state
359 // until after we notify the plugin and allow them to perform actions
360 // that may require focus
361 if (evt.eventType == kLifecycle_ANPEventType &&
362 evt.data.lifecycle.action == kLoseFocus_ANPLifecycleAction) {
363 m_hasFocus = false;
364 }
365
366 return result;
367 }
368 return 0;
369 }
370
updateEventFlags(ANPEventFlags flags)371 void PluginWidgetAndroid::updateEventFlags(ANPEventFlags flags) {
372
373 // if there are no differences then immediately return
374 if (m_eventFlags == flags) {
375 return;
376 }
377
378 Document* doc = m_pluginView->parentFrame()->document();
379 #if ENABLE(TOUCH_EVENTS)
380 if((m_eventFlags ^ flags) & kTouch_ANPEventFlag) {
381 if (flags & kTouch_ANPEventFlag)
382 doc->addListenerTypeIfNeeded(eventNames().touchstartEvent);
383 }
384 #endif
385
386 m_eventFlags = flags;
387 }
388
isAcceptingEvent(ANPEventFlag flag)389 bool PluginWidgetAndroid::isAcceptingEvent(ANPEventFlag flag) {
390 return m_eventFlags & flag;
391 }
392
sendSizeAndVisibilityEvents(const bool updateDimensions)393 void PluginWidgetAndroid::sendSizeAndVisibilityEvents(const bool updateDimensions) {
394
395 if (m_drawingModel == kOpenGL_ANPDrawingModel &&
396 !m_layer->acquireNativeWindowForContent()) {
397 m_drawEventDelayed = true;
398 return;
399 }
400
401 // TODO update the bitmap size based on the zoom? (for kBitmap_ANPDrawingModel)
402 const float zoomLevel = m_core->scale();
403
404 // notify the plugin of the new size
405 if (m_drawingModel == kOpenGL_ANPDrawingModel && updateDimensions && m_pluginWindow) {
406 PLUGIN_LOG("%s (%d,%d)[%f]", __FUNCTION__, m_pluginWindow->width,
407 m_pluginWindow->height, zoomLevel);
408 ANPEvent event;
409 SkANP::InitEvent(&event, kDraw_ANPEventType);
410 event.data.draw.model = kOpenGL_ANPDrawingModel;
411 event.data.draw.data.surface.width = m_pluginWindow->width * zoomLevel;
412 event.data.draw.data.surface.height = m_pluginWindow->height * zoomLevel;
413 sendEvent(event);
414 }
415
416 bool visible = SkIRect::Intersects(m_visibleDocRect, m_pluginBounds);
417 if(m_visible != visible) {
418
419 #if DEBUG_VISIBLE_RECTS
420 PLUGIN_LOG("%p changeVisiblity[%d] pluginBounds(%d,%d,%d,%d)",
421 m_pluginView->instance(), visible,
422 m_pluginBounds.fLeft, m_pluginBounds.fTop,
423 m_pluginBounds.fRight, m_pluginBounds.fBottom);
424 #endif
425
426 // change the visibility
427 m_visible = visible;
428 // send the event
429 ANPEvent event;
430 SkANP::InitEvent(&event, kLifecycle_ANPEventType);
431 event.data.lifecycle.action = visible ? kOnScreen_ANPLifecycleAction
432 : kOffScreen_ANPLifecycleAction;
433 sendEvent(event);
434 }
435 }
436
setVisibleScreen(const ANPRectI & visibleDocRect,float zoom)437 void PluginWidgetAndroid::setVisibleScreen(const ANPRectI& visibleDocRect, float zoom) {
438 #if DEBUG_VISIBLE_RECTS
439 PLUGIN_LOG("%s (%d,%d,%d,%d)[%f]", __FUNCTION__, visibleDocRect.left,
440 visibleDocRect.top, visibleDocRect.right,
441 visibleDocRect.bottom, zoom);
442 #endif
443 int oldScreenW = m_visibleDocRect.width();
444 int oldScreenH = m_visibleDocRect.height();
445
446 const bool zoomChanged = m_cachedZoomLevel != zoom;
447
448 // make local copies of the parameters
449 m_cachedZoomLevel = zoom;
450 m_visibleDocRect.set(visibleDocRect.left,
451 visibleDocRect.top,
452 visibleDocRect.right,
453 visibleDocRect.bottom);
454
455 int newScreenW = m_visibleDocRect.width();
456 int newScreenH = m_visibleDocRect.height();
457
458 // if the screen dimensions have changed by more than 5 pixels in either
459 // direction then recompute the plugin's visible rectangle
460 if (abs(oldScreenW - newScreenW) > 5 || abs(oldScreenH - newScreenH) > 5) {
461 PLUGIN_LOG("%s VisibleDoc old=[%d,%d] new=[%d,%d] ", __FUNCTION__,
462 oldScreenW, oldScreenH, newScreenW, newScreenH);
463 computeVisiblePluginRect();
464 }
465
466 sendSizeAndVisibilityEvents(zoomChanged);
467 }
468
visibleRect()469 ANPRectI PluginWidgetAndroid::visibleRect() {
470
471 SkIRect visibleRect;
472 visibleRect.setEmpty();
473
474 // compute the interesection of the visible screen and the plugin
475 bool visible = visibleRect.intersect(m_visibleDocRect, m_pluginBounds);
476 if (visible) {
477 // convert from absolute coordinates to the plugin's relative coordinates
478 visibleRect.offset(-m_pluginBounds.fLeft, -m_pluginBounds.fTop);
479 }
480
481 // convert from SkRect to ANPRect
482 ANPRectI result;
483 memcpy(&result, &visibleRect, sizeof(ANPRectI));
484 return result;
485 }
486
setVisibleRects(const ANPRectI rects[],int32_t count)487 void PluginWidgetAndroid::setVisibleRects(const ANPRectI rects[], int32_t count) {
488 #if DEBUG_VISIBLE_RECTS
489 PLUGIN_LOG("%s count=%d", __FUNCTION__, count);
490 #endif
491 // ensure the count does not exceed our allocated space
492 if (count > MAX_REQUESTED_RECTS)
493 count = MAX_REQUESTED_RECTS;
494
495 // store the values in member variables
496 m_requestedVisibleRectCount = count;
497 memcpy(m_requestedVisibleRects, rects, count * sizeof(rects[0]));
498
499 #if DEBUG_VISIBLE_RECTS // FIXME: this fixes bad data from the plugin
500 // take it out once plugin supplies better data
501 for (int index = 0; index < count; index++) {
502 PLUGIN_LOG("%s [%d](%d,%d,%d,%d)", __FUNCTION__, index,
503 m_requestedVisibleRects[index].left,
504 m_requestedVisibleRects[index].top,
505 m_requestedVisibleRects[index].right,
506 m_requestedVisibleRects[index].bottom);
507 if (m_requestedVisibleRects[index].left ==
508 m_requestedVisibleRects[index].right) {
509 m_requestedVisibleRects[index].right += 1;
510 }
511 if (m_requestedVisibleRects[index].top ==
512 m_requestedVisibleRects[index].bottom) {
513 m_requestedVisibleRects[index].bottom += 1;
514 }
515 }
516 #endif
517 computeVisiblePluginRect();
518 }
519
computeVisiblePluginRect()520 void PluginWidgetAndroid::computeVisiblePluginRect() {
521
522 // ensure the visibleDocRect has been set (i.e. not equal to zero)
523 if (m_visibleDocRect.isEmpty() || !m_pluginWindow || m_requestedVisibleRectCount < 1)
524 return;
525
526 // create a rect that will contain as many of the rects that will fit on screen
527 SkIRect visibleRect;
528 visibleRect.setEmpty();
529
530 for (int counter = 0; counter < m_requestedVisibleRectCount; counter++) {
531
532 ANPRectI* rect = &m_requestedVisibleRects[counter];
533
534 // create skia rect for easier manipulation and convert it to page coordinates
535 SkIRect pluginRect;
536 pluginRect.set(rect->left, rect->top, rect->right, rect->bottom);
537 pluginRect.offset(m_pluginWindow->x, m_pluginWindow->y);
538
539 // ensure the rect falls within the plugin's bounds
540 if (!m_pluginBounds.contains(pluginRect)) {
541 #if DEBUG_VISIBLE_RECTS
542 PLUGIN_LOG("%s (%d,%d,%d,%d) !contain (%d,%d,%d,%d)", __FUNCTION__,
543 m_pluginBounds.fLeft, m_pluginBounds.fTop,
544 m_pluginBounds.fRight, m_pluginBounds.fBottom,
545 pluginRect.fLeft, pluginRect.fTop,
546 pluginRect.fRight, pluginRect.fBottom);
547 // assume that the desired outcome is to clamp to the container
548 if (pluginRect.intersect(m_pluginBounds)) {
549 visibleRect = pluginRect;
550 }
551 #endif
552 continue;
553 }
554
555 // combine this new rect with the higher priority rects
556 pluginRect.join(visibleRect);
557
558 // check to see if the new rect could be made to fit within the screen
559 // bounds. If this is the highest priority rect then attempt to center
560 // even if it doesn't fit on the screen.
561 if (counter > 0 && (m_visibleDocRect.width() < pluginRect.width() ||
562 m_visibleDocRect.height() < pluginRect.height()))
563 break;
564
565 // set the new visible rect
566 visibleRect = pluginRect;
567 }
568
569 m_requestedVisibleRect = visibleRect;
570 scrollToVisiblePluginRect();
571 }
572
scrollToVisiblePluginRect()573 void PluginWidgetAndroid::scrollToVisiblePluginRect() {
574
575 if (!m_hasFocus || m_requestedVisibleRect.isEmpty() || m_visibleDocRect.isEmpty()) {
576 #if DEBUG_VISIBLE_RECTS
577 PLUGIN_LOG("%s call m_hasFocus=%d m_requestedVisibleRect.isEmpty()=%d"
578 " m_visibleDocRect.isEmpty()=%d", __FUNCTION__, m_hasFocus,
579 m_requestedVisibleRect.isEmpty(), m_visibleDocRect.isEmpty());
580 #endif
581 return;
582 }
583 // if the entire rect is already visible then we don't need to scroll
584 if (m_visibleDocRect.contains(m_requestedVisibleRect))
585 return;
586
587 // find the center of the visibleRect in document coordinates
588 int rectCenterX = m_requestedVisibleRect.fLeft + m_requestedVisibleRect.width()/2;
589 int rectCenterY = m_requestedVisibleRect.fTop + m_requestedVisibleRect.height()/2;
590
591 // position the corner of the visible doc to center the requested rect
592 int scrollDocX = MAX(0, rectCenterX - (m_visibleDocRect.width()/2));
593 int scrollDocY = MAX(0, rectCenterY - (m_visibleDocRect.height()/2));
594
595 ScrollView* scrollView = m_pluginView->parent();
596 android::WebViewCore* core = android::WebViewCore::getWebViewCore(scrollView);
597 #if DEBUG_VISIBLE_RECTS
598 PLUGIN_LOG("%s call scrollTo (%d,%d) to center (%d,%d)", __FUNCTION__,
599 scrollDocX, scrollDocX, rectCenterX, rectCenterY);
600 #endif
601 core->scrollTo(scrollDocX, scrollDocX, true);
602 }
603
requestFullScreen()604 void PluginWidgetAndroid::requestFullScreen() {
605 if (m_isFullScreen) {
606 return;
607 }
608
609 if (!m_embeddedView && m_drawingModel == kOpenGL_ANPDrawingModel) {
610 WebCore::PluginPackage* pkg = m_pluginView->plugin();
611 NPP instance = m_pluginView->instance();
612
613 jobject pluginSurface;
614 pkg->pluginFuncs()->getvalue(instance, kJavaSurface_ANPGetValue,
615 static_cast<void*>(&pluginSurface));
616
617 // create the surface, but do not add it to the view hierarchy
618 jobject tempObj = m_core->createSurface(pluginSurface);
619
620 if (tempObj) {
621 JNIEnv* env = JSC::Bindings::getJNIEnv();
622 m_embeddedView = env->NewGlobalRef(tempObj);
623 m_embeddedViewAttached = false;
624 }
625 }
626
627 if (!m_embeddedView) {
628 return;
629 }
630
631 // send event to notify plugin of full screen change
632 ANPEvent event;
633 SkANP::InitEvent(&event, kLifecycle_ANPEventType);
634 event.data.lifecycle.action = kEnterFullScreen_ANPLifecycleAction;
635 sendEvent(event);
636
637 // remove the embedded surface from the view hierarchy
638 if (m_drawingModel != kOpenGL_ANPDrawingModel)
639 m_core->destroySurface(m_embeddedView);
640
641 // add the full screen view
642 m_core->showFullScreenPlugin(m_embeddedView, m_fullScreenOrientation,
643 m_pluginView->instance());
644 m_isFullScreen = true;
645 }
646
exitFullScreen(bool pluginInitiated)647 void PluginWidgetAndroid::exitFullScreen(bool pluginInitiated) {
648 if (!m_isFullScreen || !m_embeddedView) {
649 return;
650 }
651
652 // remove the full screen surface from the view hierarchy
653 if (pluginInitiated) {
654 m_core->hideFullScreenPlugin();
655 }
656
657 // add the embedded view back
658 if (m_drawingModel != kOpenGL_ANPDrawingModel)
659 m_core->updateSurface(m_embeddedView, m_pluginWindow->x, m_pluginWindow->y,
660 m_pluginWindow->width, m_pluginWindow->height);
661
662 // send event to notify plugin of full screen change
663 ANPEvent event;
664 SkANP::InitEvent(&event, kLifecycle_ANPEventType);
665 event.data.lifecycle.action = kExitFullScreen_ANPLifecycleAction;
666 sendEvent(event);
667
668 m_isFullScreen = false;
669 }
670
setFullScreenOrientation(ANPScreenOrientation orientation)671 void PluginWidgetAndroid::setFullScreenOrientation(ANPScreenOrientation orientation) {
672
673 int internalOrienationId;
674 /* We need to validate that the input is legitimate and then convert the
675 * value from the plugin enum to the enum used by the android view system.
676 * The view system values correspond to those values for the
677 * screenOrientation attribute in R.java (see also ActivityInfo.java).
678 */
679 switch (orientation) {
680 case kFixedLandscape_ANPScreenOrientation:
681 internalOrienationId = 0;
682 break;
683 case kFixedPortrait_ANPScreenOrientation:
684 internalOrienationId = 1;
685 break;
686 case kLandscape_ANPScreenOrientation:
687 internalOrienationId = 6;
688 break;
689 case kPortrait_ANPScreenOrientation:
690 internalOrienationId = 7;
691 break;
692 default:
693 internalOrienationId = -1;
694 }
695
696 PLUGIN_LOG("%s orientation (%d)", __FUNCTION__, internalOrienationId);
697 m_fullScreenOrientation = internalOrienationId;
698 }
699
requestCenterFitZoom()700 void PluginWidgetAndroid::requestCenterFitZoom() {
701 m_core->centerFitRect(m_pluginWindow->x, m_pluginWindow->y,
702 m_pluginWindow->width, m_pluginWindow->height);
703 }
704
setPowerState(ANPPowerState powerState)705 void PluginWidgetAndroid::setPowerState(ANPPowerState powerState) {
706 if(m_powerState == powerState)
707 return;
708
709 // cleanup the old power state
710 switch (m_powerState) {
711 case kDefault_ANPPowerState:
712 break;
713 case kScreenOn_ANPPowerState:
714 m_core->keepScreenOn(false);
715 break;
716 }
717
718 // setup the new power state
719 switch (powerState) {
720 case kDefault_ANPPowerState:
721 break;
722 case kScreenOn_ANPPowerState:
723 m_core->keepScreenOn(true);
724 break;
725 }
726
727 m_powerState = powerState;
728 }
729
730