summaryrefslogtreecommitdiffstats
path: root/Source/WebKit/android/plugins/PluginWidgetAndroid.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Source/WebKit/android/plugins/PluginWidgetAndroid.cpp')
-rw-r--r--Source/WebKit/android/plugins/PluginWidgetAndroid.cpp690
1 files changed, 690 insertions, 0 deletions
diff --git a/Source/WebKit/android/plugins/PluginWidgetAndroid.cpp b/Source/WebKit/android/plugins/PluginWidgetAndroid.cpp
new file mode 100644
index 0000000..b8a10cc
--- /dev/null
+++ b/Source/WebKit/android/plugins/PluginWidgetAndroid.cpp
@@ -0,0 +1,690 @@
+/*
+ * Copyright 2008, The Android Open Source Project
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "PluginWidgetAndroid.h"
+
+#if ENABLE(TOUCH_EVENTS)
+#include "ChromeClient.h"
+#endif
+#include "Document.h"
+#include "Element.h"
+#include "Frame.h"
+#include "Page.h"
+#include "PluginPackage.h"
+#include "PluginView.h"
+#include "PluginWidgetAndroid.h"
+#include "ScrollView.h"
+#include "SkANP.h"
+#include "SkFlipPixelRef.h"
+#include "SkString.h"
+#include "SkTime.h"
+#include "WebViewCore.h"
+#include "android_graphics.h"
+#include <JNIUtility.h>
+
+// #define PLUGIN_DEBUG_LOCAL // controls the printing of log messages
+#define DEBUG_EVENTS 0 // logs event contents, return value, and processing time
+#define DEBUG_VISIBLE_RECTS 0 // temporary debug printfs and fixes
+
+// this include statement must follow the declaration of PLUGIN_DEBUG_LOCAL
+#include "PluginDebugAndroid.h"
+
+PluginWidgetAndroid::PluginWidgetAndroid(WebCore::PluginView* view)
+ : m_pluginView(view) {
+ m_flipPixelRef = NULL;
+ m_core = NULL;
+ m_drawingModel = kBitmap_ANPDrawingModel;
+ m_eventFlags = 0;
+ m_pluginWindow = NULL;
+ m_requestedVisibleRectCount = 0;
+ m_requestedVisibleRect.setEmpty();
+ m_visibleDocRect.setEmpty();
+ m_pluginBounds.setEmpty();
+ m_hasFocus = false;
+ m_isFullScreen = false;
+ m_visible = false;
+ m_cachedZoomLevel = 0;
+ m_embeddedView = NULL;
+ m_embeddedViewAttached = false;
+ m_acceptEvents = false;
+ m_isSurfaceClippedOut = false;
+ m_layer = 0;
+ m_powerState = kDefault_ANPPowerState;
+}
+
+PluginWidgetAndroid::~PluginWidgetAndroid() {
+ PLUGIN_LOG("%p Deleting Plugin", m_pluginView->instance());
+ m_acceptEvents = false;
+ if (m_core) {
+ setPowerState(kDefault_ANPPowerState);
+ m_core->removePlugin(this);
+ if (m_isFullScreen) {
+ exitFullScreen(true);
+ }
+ if (m_embeddedView) {
+ m_core->destroySurface(m_embeddedView);
+ }
+ }
+
+ // cleanup any remaining JNI References
+ JNIEnv* env = JSC::Bindings::getJNIEnv();
+ if (m_embeddedView) {
+ env->DeleteGlobalRef(m_embeddedView);
+ }
+
+ SkSafeUnref(m_flipPixelRef);
+
+ if (m_layer)
+ m_layer->unref();
+}
+
+void PluginWidgetAndroid::init(android::WebViewCore* core) {
+ m_core = core;
+ m_core->addPlugin(this);
+ m_acceptEvents = true;
+ PLUGIN_LOG("%p Initialized Plugin", m_pluginView->instance());
+}
+
+static SkBitmap::Config computeConfig(bool isTransparent) {
+ return isTransparent ? SkBitmap::kARGB_8888_Config
+ : SkBitmap::kRGB_565_Config;
+}
+
+void PluginWidgetAndroid::setWindow(NPWindow* window, bool isTransparent) {
+
+ // store the reference locally for easy lookup
+ m_pluginWindow = window;
+
+ // make a copy of the previous bounds
+ SkIRect oldPluginBounds = m_pluginBounds;
+
+ // keep a local copy of the plugin bounds because the m_pluginWindow pointer
+ // gets updated values prior to this method being called
+ m_pluginBounds.set(m_pluginWindow->x, m_pluginWindow->y,
+ m_pluginWindow->x + m_pluginWindow->width,
+ m_pluginWindow->y + m_pluginWindow->height);
+
+ PLUGIN_LOG("%p PluginBounds (%d,%d,%d,%d)", m_pluginView->instance(),
+ m_pluginBounds.fLeft, m_pluginBounds.fTop,
+ m_pluginBounds.fRight, m_pluginBounds.fBottom);
+
+ const bool boundsChanged = m_pluginBounds != oldPluginBounds;
+
+ //TODO hack to ensure that we grab the most recent screen dimensions and scale
+ ANPRectI screenCoords;
+ m_core->getVisibleScreen(screenCoords);
+ float scale = m_core->scale();
+ bool scaleChanged = m_cachedZoomLevel != scale;
+ setVisibleScreen(screenCoords, scale);
+
+ // if the scale changed then setVisibleScreen will call this function and
+ // this call will potentially fire a duplicate draw event
+ if (!scaleChanged) {
+ sendSizeAndVisibilityEvents(boundsChanged);
+ }
+ layoutSurface(boundsChanged);
+
+ if (m_drawingModel != kSurface_ANPDrawingModel) {
+ SkSafeUnref(m_flipPixelRef);
+ m_flipPixelRef = new SkFlipPixelRef(computeConfig(isTransparent),
+ window->width, window->height);
+ }
+}
+
+bool PluginWidgetAndroid::setDrawingModel(ANPDrawingModel model) {
+
+ if (model == kOpenGL_ANPDrawingModel && m_layer == 0) {
+ JNIEnv* env = JSC::Bindings::getJNIEnv();
+ jobject webview = m_core->getWebViewJavaObject();
+ jobject weakWebViewRef = 0;
+ if (webview)
+ weakWebViewRef = env->NewWeakGlobalRef(webview);
+ m_layer = new WebCore::MediaLayer(weakWebViewRef);
+ }
+ else if (model != kOpenGL_ANPDrawingModel && m_layer != 0) {
+ m_layer->unref();
+ m_layer = 0;
+ }
+
+ if (m_drawingModel != model) {
+ // Trigger layer computation in RenderLayerCompositor
+ m_pluginView->getElement()->setNeedsStyleRecalc(SyntheticStyleChange);
+ }
+
+ m_drawingModel = model;
+ return true;
+}
+
+// returned rect is in the page coordinate
+bool PluginWidgetAndroid::isDirty(SkIRect* rect) const {
+ // nothing to report if we haven't had setWindow() called yet
+ if (NULL == m_flipPixelRef) {
+ return false;
+ }
+
+ const SkRegion& dirty = m_flipPixelRef->dirtyRgn();
+ if (dirty.isEmpty()) {
+ return false;
+ } else {
+ if (rect) {
+ *rect = dirty.getBounds();
+ rect->offset(m_pluginWindow->x, m_pluginWindow->y);
+ }
+ return true;
+ }
+}
+
+void PluginWidgetAndroid::inval(const WebCore::IntRect& rect,
+ bool signalRedraw) {
+ // nothing to do if we haven't had setWindow() called yet. m_flipPixelRef
+ // will also be null if this is a Surface model.
+ if (NULL == m_flipPixelRef) {
+ return;
+ }
+
+ m_flipPixelRef->inval(rect);
+
+ if (signalRedraw && m_flipPixelRef->isDirty()) {
+ m_core->invalPlugin(this);
+ }
+}
+
+void PluginWidgetAndroid::viewInvalidate() {
+ WebCore::IntRect rect(m_pluginBounds.fLeft, m_pluginBounds.fTop,
+ m_pluginBounds.width(), m_pluginBounds.height());
+ m_core->viewInvalidate(rect);
+}
+
+void PluginWidgetAndroid::draw(SkCanvas* canvas) {
+ if (NULL == m_flipPixelRef || !m_flipPixelRef->isDirty()) {
+ return;
+ }
+
+ SkAutoFlipUpdate update(m_flipPixelRef);
+ const SkBitmap& bitmap = update.bitmap();
+ const SkRegion& dirty = update.dirty();
+
+ ANPEvent event;
+ SkANP::InitEvent(&event, kDraw_ANPEventType);
+
+ event.data.draw.model = m_drawingModel;
+ SkANP::SetRect(&event.data.draw.clip, dirty.getBounds());
+
+ switch (m_drawingModel) {
+ case kBitmap_ANPDrawingModel: {
+ WebCore::PluginPackage* pkg = m_pluginView->plugin();
+ NPP instance = m_pluginView->instance();
+
+ if (SkANP::SetBitmap(&event.data.draw.data.bitmap,
+ bitmap) &&
+ pkg->pluginFuncs()->event(instance, &event)) {
+
+ if (canvas && m_pluginWindow) {
+ SkBitmap bm(bitmap);
+ bm.setPixelRef(m_flipPixelRef);
+ canvas->drawBitmap(bm, 0, 0);
+ }
+ }
+ break;
+ }
+ default:
+ break;
+ }
+}
+
+void PluginWidgetAndroid::setSurfaceClip(const SkIRect& clip) {
+
+ if (m_drawingModel != kSurface_ANPDrawingModel)
+ return;
+
+ /* don't display surfaces that are either entirely clipped or only 1x1 in
+ size. It appears that when an element is absolutely positioned and has
+ been completely clipped in CSS that webkit still sends a clip of 1x1.
+ */
+ bool clippedOut = (clip.width() <= 1 && clip.height() <= 1);
+ if(clippedOut != m_isSurfaceClippedOut) {
+ m_isSurfaceClippedOut = clippedOut;
+ layoutSurface();
+ }
+}
+
+void PluginWidgetAndroid::layoutSurface(bool pluginBoundsChanged) {
+
+ if (m_drawingModel != kSurface_ANPDrawingModel)
+ return;
+ if (!m_pluginWindow)
+ return;
+
+
+ bool displayPlugin = m_pluginView->isVisible() && !m_isSurfaceClippedOut;
+ PLUGIN_LOG("%p DisplayPlugin[%d] visible=[%d] clipped=[%d]",
+ m_pluginView->instance(), displayPlugin,
+ m_pluginView->isVisible(), m_isSurfaceClippedOut);
+
+ // if the surface does not exist then create a new surface
+ if (!m_embeddedView && displayPlugin) {
+
+ WebCore::PluginPackage* pkg = m_pluginView->plugin();
+ NPP instance = m_pluginView->instance();
+
+ jobject pluginSurface;
+ pkg->pluginFuncs()->getvalue(instance, kJavaSurface_ANPGetValue,
+ static_cast<void*>(&pluginSurface));
+
+ jobject tempObj = m_core->addSurface(pluginSurface,
+ m_pluginWindow->x, m_pluginWindow->y,
+ m_pluginWindow->width, m_pluginWindow->height);
+
+ if (tempObj) {
+ JNIEnv* env = JSC::Bindings::getJNIEnv();
+ m_embeddedView = env->NewGlobalRef(tempObj);
+ m_embeddedViewAttached = true;
+ }
+ // if the view is unattached but visible then attach it
+ } else if (m_embeddedView && !m_embeddedViewAttached && displayPlugin && !m_isFullScreen) {
+ m_core->updateSurface(m_embeddedView, m_pluginWindow->x, m_pluginWindow->y,
+ m_pluginWindow->width, m_pluginWindow->height);
+ m_embeddedViewAttached = true;
+ // if the view is attached but invisible then remove it
+ } else if (m_embeddedView && m_embeddedViewAttached && !displayPlugin) {
+ m_core->destroySurface(m_embeddedView);
+ m_embeddedViewAttached = false;
+ // if the plugin's bounds have changed and it's visible then update it
+ } else if (pluginBoundsChanged && displayPlugin && !m_isFullScreen) {
+ m_core->updateSurface(m_embeddedView, m_pluginWindow->x, m_pluginWindow->y,
+ m_pluginWindow->width, m_pluginWindow->height);
+
+ }
+}
+
+int16_t PluginWidgetAndroid::sendEvent(const ANPEvent& evt) {
+ if (!m_acceptEvents)
+ return 0;
+ WebCore::PluginPackage* pkg = m_pluginView->plugin();
+ NPP instance = m_pluginView->instance();
+ // "missing" plugins won't have these
+ if (pkg && instance) {
+
+ // if the plugin is gaining focus then update our state now to allow
+ // the plugin's event handler to perform actions that require focus
+ if (evt.eventType == kLifecycle_ANPEventType &&
+ evt.data.lifecycle.action == kGainFocus_ANPLifecycleAction) {
+ m_hasFocus = true;
+ }
+
+#if DEBUG_EVENTS
+ SkMSec startTime = SkTime::GetMSecs();
+#endif
+
+ // make a localCopy since the actual plugin may not respect its constness,
+ // and so we don't want our caller to have its param modified
+ ANPEvent localCopy = evt;
+ int16_t result = pkg->pluginFuncs()->event(instance, &localCopy);
+
+#if DEBUG_EVENTS
+ SkMSec endTime = SkTime::GetMSecs();
+ PLUGIN_LOG_EVENT(instance, &evt, result, endTime - startTime);
+#endif
+
+ // if the plugin is losing focus then delay the update of our state
+ // until after we notify the plugin and allow them to perform actions
+ // that may require focus
+ if (evt.eventType == kLifecycle_ANPEventType &&
+ evt.data.lifecycle.action == kLoseFocus_ANPLifecycleAction) {
+ m_hasFocus = false;
+ }
+
+ return result;
+ }
+ return 0;
+}
+
+void PluginWidgetAndroid::updateEventFlags(ANPEventFlags flags) {
+
+ // if there are no differences then immediately return
+ if (m_eventFlags == flags) {
+ return;
+ }
+
+ Document* doc = m_pluginView->parentFrame()->document();
+#if ENABLE(TOUCH_EVENTS)
+ if((m_eventFlags ^ flags) & kTouch_ANPEventFlag) {
+ if (flags & kTouch_ANPEventFlag)
+ doc->addListenerTypeIfNeeded(eventNames().touchstartEvent);
+ }
+#endif
+
+ m_eventFlags = flags;
+}
+
+bool PluginWidgetAndroid::isAcceptingEvent(ANPEventFlag flag) {
+ return m_eventFlags & flag;
+}
+
+void PluginWidgetAndroid::sendSizeAndVisibilityEvents(const bool updateDimensions) {
+ // TODO update the bitmap size based on the zoom? (for kBitmap_ANPDrawingModel)
+
+ const float zoomLevel = m_core->scale();
+
+ // notify the plugin of the new size
+ if (m_drawingModel == kOpenGL_ANPDrawingModel && updateDimensions && m_pluginWindow) {
+ PLUGIN_LOG("%s (%d,%d)[%f]", __FUNCTION__, m_pluginWindow->width,
+ m_pluginWindow->height, zoomLevel);
+ ANPEvent event;
+ SkANP::InitEvent(&event, kDraw_ANPEventType);
+ event.data.draw.model = kOpenGL_ANPDrawingModel;
+ event.data.draw.data.surface.width = m_pluginWindow->width * zoomLevel;
+ event.data.draw.data.surface.height = m_pluginWindow->height * zoomLevel;
+ sendEvent(event);
+ }
+
+ bool visible = SkIRect::Intersects(m_visibleDocRect, m_pluginBounds);
+ if(m_visible != visible) {
+
+#if DEBUG_VISIBLE_RECTS
+ PLUGIN_LOG("%p changeVisiblity[%d] pluginBounds(%d,%d,%d,%d)",
+ m_pluginView->instance(), visible,
+ m_pluginBounds.fLeft, m_pluginBounds.fTop,
+ m_pluginBounds.fRight, m_pluginBounds.fBottom);
+#endif
+
+ // change the visibility
+ m_visible = visible;
+ // send the event
+ ANPEvent event;
+ SkANP::InitEvent(&event, kLifecycle_ANPEventType);
+ event.data.lifecycle.action = visible ? kOnScreen_ANPLifecycleAction
+ : kOffScreen_ANPLifecycleAction;
+ sendEvent(event);
+ }
+}
+
+void PluginWidgetAndroid::setVisibleScreen(const ANPRectI& visibleDocRect, float zoom) {
+#if DEBUG_VISIBLE_RECTS
+ PLUGIN_LOG("%s (%d,%d,%d,%d)[%f]", __FUNCTION__, visibleDocRect.left,
+ visibleDocRect.top, visibleDocRect.right,
+ visibleDocRect.bottom, zoom);
+#endif
+ int oldScreenW = m_visibleDocRect.width();
+ int oldScreenH = m_visibleDocRect.height();
+
+ const bool zoomChanged = m_cachedZoomLevel != zoom;
+
+ // make local copies of the parameters
+ m_cachedZoomLevel = zoom;
+ m_visibleDocRect.set(visibleDocRect.left,
+ visibleDocRect.top,
+ visibleDocRect.right,
+ visibleDocRect.bottom);
+
+ int newScreenW = m_visibleDocRect.width();
+ int newScreenH = m_visibleDocRect.height();
+
+ // if the screen dimensions have changed by more than 5 pixels in either
+ // direction then recompute the plugin's visible rectangle
+ if (abs(oldScreenW - newScreenW) > 5 || abs(oldScreenH - newScreenH) > 5) {
+ PLUGIN_LOG("%s VisibleDoc old=[%d,%d] new=[%d,%d] ", __FUNCTION__,
+ oldScreenW, oldScreenH, newScreenW, newScreenH);
+ computeVisiblePluginRect();
+ }
+
+ sendSizeAndVisibilityEvents(zoomChanged);
+}
+
+ANPRectI PluginWidgetAndroid::visibleRect() {
+
+ SkIRect visibleRect;
+ visibleRect.setEmpty();
+
+ // compute the interesection of the visible screen and the plugin
+ bool visible = visibleRect.intersect(m_visibleDocRect, m_pluginBounds);
+ if (visible) {
+ // convert from absolute coordinates to the plugin's relative coordinates
+ visibleRect.offset(-m_pluginBounds.fLeft, -m_pluginBounds.fTop);
+ }
+
+ // convert from SkRect to ANPRect
+ ANPRectI result;
+ memcpy(&result, &visibleRect, sizeof(ANPRectI));
+ return result;
+}
+
+void PluginWidgetAndroid::setVisibleRects(const ANPRectI rects[], int32_t count) {
+#if DEBUG_VISIBLE_RECTS
+ PLUGIN_LOG("%s count=%d", __FUNCTION__, count);
+#endif
+ // ensure the count does not exceed our allocated space
+ if (count > MAX_REQUESTED_RECTS)
+ count = MAX_REQUESTED_RECTS;
+
+ // store the values in member variables
+ m_requestedVisibleRectCount = count;
+ memcpy(m_requestedVisibleRects, rects, count * sizeof(rects[0]));
+
+#if DEBUG_VISIBLE_RECTS // FIXME: this fixes bad data from the plugin
+ // take it out once plugin supplies better data
+ for (int index = 0; index < count; index++) {
+ PLUGIN_LOG("%s [%d](%d,%d,%d,%d)", __FUNCTION__, index,
+ m_requestedVisibleRects[index].left,
+ m_requestedVisibleRects[index].top,
+ m_requestedVisibleRects[index].right,
+ m_requestedVisibleRects[index].bottom);
+ if (m_requestedVisibleRects[index].left ==
+ m_requestedVisibleRects[index].right) {
+ m_requestedVisibleRects[index].right += 1;
+ }
+ if (m_requestedVisibleRects[index].top ==
+ m_requestedVisibleRects[index].bottom) {
+ m_requestedVisibleRects[index].bottom += 1;
+ }
+ }
+#endif
+ computeVisiblePluginRect();
+}
+
+void PluginWidgetAndroid::computeVisiblePluginRect() {
+
+ // ensure the visibleDocRect has been set (i.e. not equal to zero)
+ if (m_visibleDocRect.isEmpty() || !m_pluginWindow || m_requestedVisibleRectCount < 1)
+ return;
+
+ // create a rect that will contain as many of the rects that will fit on screen
+ SkIRect visibleRect;
+ visibleRect.setEmpty();
+
+ for (int counter = 0; counter < m_requestedVisibleRectCount; counter++) {
+
+ ANPRectI* rect = &m_requestedVisibleRects[counter];
+
+ // create skia rect for easier manipulation and convert it to page coordinates
+ SkIRect pluginRect;
+ pluginRect.set(rect->left, rect->top, rect->right, rect->bottom);
+ pluginRect.offset(m_pluginWindow->x, m_pluginWindow->y);
+
+ // ensure the rect falls within the plugin's bounds
+ if (!m_pluginBounds.contains(pluginRect)) {
+#if DEBUG_VISIBLE_RECTS
+ PLUGIN_LOG("%s (%d,%d,%d,%d) !contain (%d,%d,%d,%d)", __FUNCTION__,
+ m_pluginBounds.fLeft, m_pluginBounds.fTop,
+ m_pluginBounds.fRight, m_pluginBounds.fBottom,
+ pluginRect.fLeft, pluginRect.fTop,
+ pluginRect.fRight, pluginRect.fBottom);
+ // assume that the desired outcome is to clamp to the container
+ if (pluginRect.intersect(m_pluginBounds)) {
+ visibleRect = pluginRect;
+ }
+#endif
+ continue;
+ }
+
+ // combine this new rect with the higher priority rects
+ pluginRect.join(visibleRect);
+
+ // check to see if the new rect could be made to fit within the screen
+ // bounds. If this is the highest priority rect then attempt to center
+ // even if it doesn't fit on the screen.
+ if (counter > 0 && (m_visibleDocRect.width() < pluginRect.width() ||
+ m_visibleDocRect.height() < pluginRect.height()))
+ break;
+
+ // set the new visible rect
+ visibleRect = pluginRect;
+ }
+
+ m_requestedVisibleRect = visibleRect;
+ scrollToVisiblePluginRect();
+}
+
+void PluginWidgetAndroid::scrollToVisiblePluginRect() {
+
+ if (!m_hasFocus || m_requestedVisibleRect.isEmpty() || m_visibleDocRect.isEmpty()) {
+#if DEBUG_VISIBLE_RECTS
+ PLUGIN_LOG("%s call m_hasFocus=%d m_requestedVisibleRect.isEmpty()=%d"
+ " m_visibleDocRect.isEmpty()=%d", __FUNCTION__, m_hasFocus,
+ m_requestedVisibleRect.isEmpty(), m_visibleDocRect.isEmpty());
+#endif
+ return;
+ }
+ // if the entire rect is already visible then we don't need to scroll
+ if (m_visibleDocRect.contains(m_requestedVisibleRect))
+ return;
+
+ // find the center of the visibleRect in document coordinates
+ int rectCenterX = m_requestedVisibleRect.fLeft + m_requestedVisibleRect.width()/2;
+ int rectCenterY = m_requestedVisibleRect.fTop + m_requestedVisibleRect.height()/2;
+
+ // find document coordinates for center of the visible screen
+ int visibleDocCenterX = m_visibleDocRect.fLeft + m_visibleDocRect.width()/2;
+ int visibleDocCenterY = m_visibleDocRect.fTop + m_visibleDocRect.height()/2;
+
+ //compute the delta of the two points and scale to screen coordinates
+ int deltaX = rectCenterX - visibleDocCenterX;
+ int deltaY = rectCenterY - visibleDocCenterY;
+
+ ScrollView* scrollView = m_pluginView->parent();
+ android::WebViewCore* core = android::WebViewCore::getWebViewCore(scrollView);
+#if DEBUG_VISIBLE_RECTS
+ PLUGIN_LOG("%s call scrollBy (%d,%d)", __FUNCTION__, deltaX, deltaY);
+#endif
+ core->scrollTo(rectCenterX, rectCenterY, true);
+}
+
+void PluginWidgetAndroid::requestFullScreen() {
+ if (m_isFullScreen) {
+ return;
+ }
+
+ if (!m_embeddedView && m_drawingModel == kOpenGL_ANPDrawingModel) {
+ WebCore::PluginPackage* pkg = m_pluginView->plugin();
+ NPP instance = m_pluginView->instance();
+
+ jobject pluginSurface;
+ pkg->pluginFuncs()->getvalue(instance, kJavaSurface_ANPGetValue,
+ static_cast<void*>(&pluginSurface));
+
+ // create the surface, but do not add it to the view hierarchy
+ jobject tempObj = m_core->createSurface(pluginSurface);
+
+ if (tempObj) {
+ JNIEnv* env = JSC::Bindings::getJNIEnv();
+ m_embeddedView = env->NewGlobalRef(tempObj);
+ m_embeddedViewAttached = false;
+ }
+ }
+
+ if (!m_embeddedView) {
+ return;
+ }
+
+ // send event to notify plugin of full screen change
+ ANPEvent event;
+ SkANP::InitEvent(&event, kLifecycle_ANPEventType);
+ event.data.lifecycle.action = kEnterFullScreen_ANPLifecycleAction;
+ sendEvent(event);
+
+ // remove the embedded surface from the view hierarchy
+ if (m_drawingModel != kOpenGL_ANPDrawingModel)
+ m_core->destroySurface(m_embeddedView);
+
+ // add the full screen view
+ m_core->showFullScreenPlugin(m_embeddedView, m_pluginView->instance());
+ m_isFullScreen = true;
+}
+
+void PluginWidgetAndroid::exitFullScreen(bool pluginInitiated) {
+ if (!m_isFullScreen || !m_embeddedView) {
+ return;
+ }
+
+ // remove the full screen surface from the view hierarchy
+ if (pluginInitiated) {
+ m_core->hideFullScreenPlugin();
+ }
+
+ // add the embedded view back
+ if (m_drawingModel != kOpenGL_ANPDrawingModel)
+ m_core->updateSurface(m_embeddedView, m_pluginWindow->x, m_pluginWindow->y,
+ m_pluginWindow->width, m_pluginWindow->height);
+
+ // send event to notify plugin of full screen change
+ ANPEvent event;
+ SkANP::InitEvent(&event, kLifecycle_ANPEventType);
+ event.data.lifecycle.action = kExitFullScreen_ANPLifecycleAction;
+ sendEvent(event);
+
+ m_isFullScreen = false;
+}
+
+void PluginWidgetAndroid::requestCenterFitZoom() {
+ m_core->centerFitRect(m_pluginWindow->x, m_pluginWindow->y,
+ m_pluginWindow->width, m_pluginWindow->height);
+}
+
+void PluginWidgetAndroid::setPowerState(ANPPowerState powerState) {
+ if(m_powerState == powerState)
+ return;
+
+ // cleanup the old power state
+ switch (m_powerState) {
+ case kDefault_ANPPowerState:
+ break;
+ case kScreenOn_ANPPowerState:
+ m_core->keepScreenOn(false);
+ break;
+ }
+
+ // setup the new power state
+ switch (powerState) {
+ case kDefault_ANPPowerState:
+ break;
+ case kScreenOn_ANPPowerState:
+ m_core->keepScreenOn(true);
+ break;
+ }
+
+ m_powerState = powerState;
+}
+