• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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