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