summaryrefslogtreecommitdiffstats
path: root/WebCore/plugins/android/PluginViewAndroid.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'WebCore/plugins/android/PluginViewAndroid.cpp')
-rw-r--r--WebCore/plugins/android/PluginViewAndroid.cpp569
1 files changed, 569 insertions, 0 deletions
diff --git a/WebCore/plugins/android/PluginViewAndroid.cpp b/WebCore/plugins/android/PluginViewAndroid.cpp
new file mode 100644
index 0000000..7e3e479
--- /dev/null
+++ b/WebCore/plugins/android/PluginViewAndroid.cpp
@@ -0,0 +1,569 @@
+/*
+ * Copyright 2009, The Android Open Source Project
+ * Copyright (C) 2006, 2007 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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 APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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.
+ */
+#define LOG_TAG "WebCore"
+
+#include "config.h"
+#include "PluginView.h"
+
+#include "Document.h"
+#include "Element.h"
+#include "EventNames.h"
+#include "FrameLoader.h"
+#include "FrameLoadRequest.h"
+#include "FrameTree.h"
+#include "Frame.h"
+#include "FrameView.h"
+#include "GraphicsContext.h"
+#include "HTMLNames.h"
+#include "HTMLPlugInElement.h"
+#include "Image.h"
+#include "KeyboardEvent.h"
+#include "MIMETypeRegistry.h"
+#include "MouseEvent.h"
+#include "NotImplemented.h"
+#include "Page.h"
+#include "PlatformGraphicsContext.h"
+#include "PlatformKeyboardEvent.h"
+#include "PluginMainThreadScheduler.h"
+#include "PluginPackage.h"
+// #include "kjs_binding.h"
+// #include "kjs_proxy.h"
+#include "android_graphics.h"
+#include "SkCanvas.h"
+#include "npruntime_impl.h"
+#include "runtime_root.h"
+#include "utils/SystemClock.h"
+#include "ScriptController.h"
+#include "Settings.h"
+#include <runtime/JSLock.h>
+// #include <kjs/value.h>
+#include <wtf/ASCIICType.h>
+#include "runtime.h"
+#include "WebViewCore.h"
+
+#include "PluginDebug.h"
+#include "PluginDebugAndroid.h"
+#include "PluginViewBridgeAndroid.h"
+#include "PluginWidgetAndroid.h"
+
+#include "android_npapi.h"
+#include "SkANP.h"
+#include "SkFlipPixelRef.h"
+
+///////////////////////////////////////////////////////////////////////////////
+
+extern void ANPAudioTrackInterfaceV0_Init(ANPInterface* value);
+extern void ANPCanvasInterfaceV0_Init(ANPInterface* value);
+extern void ANPLogInterfaceV0_Init(ANPInterface* value);
+extern void ANPOffscreenInterfaceV0_Init(ANPInterface* value);
+extern void ANPPaintInterfaceV0_Init(ANPInterface* value);
+extern void ANPTypefaceInterfaceV0_Init(ANPInterface* value);
+extern void ANPWindowInterfaceV0_Init(ANPInterface* value);
+
+struct VarProcPair {
+ int enumValue;
+ size_t size;
+ void (*proc)(ANPInterface*);
+};
+
+#define VARPROCLINE(name) \
+ k##name##_ANPGetValue, sizeof(ANP##name), ANP##name##_Init
+
+static const VarProcPair gVarProcs[] = {
+ { VARPROCLINE(AudioTrackInterfaceV0) },
+ { VARPROCLINE(LogInterfaceV0) },
+ { VARPROCLINE(CanvasInterfaceV0) },
+ { VARPROCLINE(PaintInterfaceV0) },
+ { VARPROCLINE(TypefaceInterfaceV0) },
+ { VARPROCLINE(WindowInterfaceV0) },
+};
+
+/* return true if var was an interface request (error will be set accordingly)
+ return false if var is not a recognized interface (and ignore error param)
+ */
+static bool anp_getInterface(NPNVariable var, void* value, NPError* error) {
+ const VarProcPair* iter = gVarProcs;
+ const VarProcPair* stop = gVarProcs + SK_ARRAY_COUNT(gVarProcs);
+ while (iter < stop) {
+ if (iter->enumValue == var) {
+ ANPInterface* i = reinterpret_cast<ANPInterface*>(value);
+ if (i->inSize < iter->size) {
+ SkDebugf("------- interface %d, expected size %d, allocated %d\n",
+ var, iter->size, i->inSize);
+ *error = NPERR_INCOMPATIBLE_VERSION_ERROR;
+ } else {
+ iter->proc(i);
+ *error = NPERR_NO_ERROR;
+ }
+ return true;
+ }
+ iter += 1;
+ }
+ SkDebugf("------ unknown NPNVariable %d\n", var);
+ return false;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+using JSC::ExecState;
+using JSC::Interpreter;
+using JSC::JSLock;
+using JSC::JSObject;
+using JSC::JSValue;
+using JSC::UString;
+
+using std::min;
+
+using namespace WTF;
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+void PluginView::platformInit()
+{
+ setPlatformWidget(new PluginViewBridgeAndroid());
+
+ m_isWindowed = false; // we don't support windowed yet
+
+ m_window = new PluginWidgetAndroid(this);
+
+ m_npWindow.type = NPWindowTypeDrawable;
+ m_npWindow.window = 0;
+}
+
+PluginView::~PluginView()
+{
+ stop();
+
+ deleteAllValues(m_requests);
+
+ freeStringArray(m_paramNames, m_paramCount);
+ freeStringArray(m_paramValues, m_paramCount);
+
+ m_parentFrame->script()->cleanupScriptObjectsForPlugin(this);
+
+// Since we have no legacy plugins to check, we ignore the quirks check
+// if (m_plugin && !m_plugin->quirks().contains(PluginQuirkDontUnloadPlugin))
+ if (m_plugin) {
+ m_plugin->unload();
+ }
+ delete m_window;
+}
+
+void PluginView::init()
+{
+ if (m_haveInitialized)
+ return;
+ m_haveInitialized = true;
+
+ android::WebViewCore* c = android::WebViewCore::getWebViewCore(this->parent());
+ m_window->init(c);
+
+ if (!m_plugin) {
+ ASSERT(m_status == PluginStatusCanNotFindPlugin);
+ return;
+ }
+
+ if (!m_plugin->load()) {
+ m_plugin = 0;
+ m_status = PluginStatusCanNotLoadPlugin;
+ return;
+ }
+
+ if (!start()) {
+ m_status = PluginStatusCanNotLoadPlugin;
+ return;
+ }
+
+ m_status = PluginStatusLoadedSuccessfully;
+}
+
+void PluginView::handleMouseEvent(MouseEvent* event)
+{
+ const AtomicString& type = event->type();
+ bool isDown = (eventNames().mousedownEvent == type);
+ bool isUp = (eventNames().mouseupEvent == type);
+ if (!isDown && !isUp) {
+ return;
+ }
+
+ ANPEvent evt;
+ SkANP::InitEvent(&evt, kTouch_ANPEventType);
+
+ evt.data.touch.action = isDown ? kDown_ANPTouchAction : kUp_ANPTouchAction;
+ evt.data.touch.modifiers = 0; // todo
+ // these are relative to plugin
+ evt.data.touch.x = event->pageX() - m_npWindow.x;
+ evt.data.touch.y = event->pageY() - m_npWindow.y;
+ if (m_plugin->pluginFuncs()->event(m_instance, &evt)) {
+ event->setDefaultHandled();
+ }
+}
+
+static ANPKeyModifier make_modifiers(bool shift, bool alt) {
+ ANPKeyModifier mod = 0;
+ if (shift) {
+ mod |= kShift_ANPKeyModifier;
+ }
+ if (alt) {
+ mod |= kAlt_ANPKeyModifier;
+ }
+ return mod;
+}
+
+void PluginView::handleKeyboardEvent(KeyboardEvent* event)
+{
+ const PlatformKeyboardEvent* pke = event->keyEvent();
+ if (NULL == pke) {
+ return;
+ }
+
+ ANPEvent evt;
+ SkANP::InitEvent(&evt, kKey_ANPEventType);
+
+ switch (pke->type()) {
+ case PlatformKeyboardEvent::KeyDown:
+#ifdef TRACE_KEY_EVENTS
+ SkDebugf("--------- KeyDown, ignore\n");
+#endif
+ return;
+ case PlatformKeyboardEvent::RawKeyDown:
+ evt.data.key.action = kDown_ANPKeyAction;
+ break;
+ case PlatformKeyboardEvent::Char:
+#ifdef TRACE_KEY_EVENTS
+ SkDebugf("--------- Char, ignore\n");
+#endif
+ return;
+ case PlatformKeyboardEvent::KeyUp:
+ evt.data.key.action = kUp_ANPKeyAction;
+ break;
+ default:
+#ifdef TRACE_KEY_EVENTS
+ SkDebugf("------ unexpected keyevent type %d\n", pke->type());
+#endif
+ return;
+ }
+ evt.data.key.nativeCode = pke->nativeVirtualKeyCode();
+ evt.data.key.virtualCode = pke->windowsVirtualKeyCode();
+ evt.data.key.repeatCount = pke->repeatCount();
+ evt.data.key.modifiers = make_modifiers(pke->shiftKey(), pke->altKey());
+ evt.data.key.unichar = pke->unichar();
+
+ if (m_plugin->pluginFuncs()->event(m_instance, &evt)) {
+ event->setDefaultHandled();
+ }
+}
+
+NPError PluginView::handlePostReadFile(Vector<char>& buffer, uint32 len, const char* buf)
+{
+ notImplemented();
+ return NPERR_GENERIC_ERROR;
+}
+
+NPError PluginView::getValueStatic(NPNVariable variable, void* value)
+{
+ // our interface query is valid with no NPP instance
+ NPError error = NPERR_GENERIC_ERROR;
+ (void)anp_getInterface(variable, value, &error);
+ return error;
+}
+
+void PluginView::setParent(ScrollView* parent)
+{
+ Widget::setParent(parent);
+
+ if (parent)
+ init();
+}
+
+void PluginView::setNPWindowRect(const IntRect& rect)
+{
+ if (!m_isStarted)
+ return;
+
+ const int width = rect.width();
+ const int height = rect.height();
+
+ IntPoint p = static_cast<FrameView*>(parent())->contentsToWindow(rect.location());
+ m_npWindow.x = p.x();
+ m_npWindow.y = p.y();
+
+ m_npWindow.width = width;
+ m_npWindow.height = height;
+
+ m_npWindow.clipRect.left = 0;
+ m_npWindow.clipRect.top = 0;
+ m_npWindow.clipRect.right = width;
+ m_npWindow.clipRect.bottom = height;
+
+ if (m_plugin->pluginFuncs()->setwindow) {
+ JSC::JSLock::DropAllLocks dropAllLocks(false);
+ setCallingPlugin(true);
+ m_plugin->pluginFuncs()->setwindow(m_instance, &m_npWindow);
+ setCallingPlugin(false);
+ }
+
+ m_window->setWindow(m_npWindow.x, m_npWindow.y, width, height,
+ m_isTransparent);
+}
+
+void PluginView::stop()
+{
+ if (!m_isStarted)
+ return;
+
+ HashSet<RefPtr<PluginStream> > streams = m_streams;
+ HashSet<RefPtr<PluginStream> >::iterator end = streams.end();
+ for (HashSet<RefPtr<PluginStream> >::iterator it = streams.begin(); it != end; ++it) {
+ (*it)->stop();
+ disconnectStream((*it).get());
+ }
+
+ ASSERT(m_streams.isEmpty());
+
+ m_isStarted = false;
+
+ JSC::JSLock::DropAllLocks dropAllLocks(false);
+
+ PluginMainThreadScheduler::scheduler().unregisterPlugin(m_instance);
+
+ // Destroy the plugin
+ NPSavedData* savedData = 0;
+ setCallingPlugin(true);
+ NPError npErr = m_plugin->pluginFuncs()->destroy(m_instance, &savedData);
+ setCallingPlugin(false);
+ LOG_NPERROR(npErr);
+
+ if (savedData) {
+ if (savedData->buf)
+ NPN_MemFree(savedData->buf);
+ NPN_MemFree(savedData);
+ }
+
+ m_instance->pdata = 0;
+}
+
+const char* PluginView::userAgentStatic()
+{
+ return 0;
+}
+
+const char* PluginView::userAgent()
+{
+ if (m_userAgent.isNull())
+ m_userAgent = m_parentFrame->loader()->userAgent(m_url).utf8();
+ return m_userAgent.data();
+}
+
+NPError PluginView::getValue(NPNVariable variable, void* value)
+{
+ switch (variable) {
+ case NPNVWindowNPObject: {
+ NPObject* windowScriptObject =
+ m_parentFrame->script()->windowScriptNPObject();
+
+ // Return value is expected to be retained, as described
+ // here:
+ // <http://www.mozilla.org/projects/plugin/npruntime.html>
+ if (windowScriptObject)
+ _NPN_RetainObject(windowScriptObject);
+
+ void** v = (void**)value;
+ *v = windowScriptObject;
+
+ return NPERR_NO_ERROR;
+ }
+
+ case NPNVPluginElementNPObject: {
+ NPObject* pluginScriptObject = 0;
+
+ if (m_element->hasTagName(appletTag) ||
+ m_element->hasTagName(embedTag) ||
+ m_element->hasTagName(objectTag)) {
+ HTMLPlugInElement* pluginElement =
+ static_cast<HTMLPlugInElement*>(m_element);
+ pluginScriptObject = pluginElement->getNPObject();
+ }
+
+ // Return value is expected to be retained, as described
+ // here:
+ // <http://www.mozilla.org/projects/plugin/npruntime.html>
+ if (pluginScriptObject)
+ _NPN_RetainObject(pluginScriptObject);
+
+ void** v = (void**)value;
+ *v = pluginScriptObject;
+
+ return NPERR_NO_ERROR;
+ }
+
+ case NPNVnetscapeWindow: {
+ // Return the top level WebView Java object associated
+ // with this instance.
+ jobject *retObject = static_cast<jobject*>(value);
+ *retObject = android::WebViewCore::getWebViewCore(parent())->getWebViewJavaObject();
+ return NPERR_NO_ERROR;
+ }
+
+ case kSupportedDrawingModel_ANPGetValue: {
+ uint32_t* bits = reinterpret_cast<uint32_t*>(value);
+ *bits = (1 << kBitmap_ANPDrawingModel);
+ return NPERR_NO_ERROR;
+ }
+
+ default: {
+ NPError error = NPERR_GENERIC_ERROR;
+ (void)anp_getInterface(variable, value, &error);
+ return error;
+ }
+ }
+}
+
+NPError PluginView::platformSetValue(NPPVariable variable, void* value)
+{
+ NPError error = NPERR_GENERIC_ERROR;
+
+ switch (variable) {
+ case kRequestDrawingModel_ANPSetValue: {
+ ANPDrawingModel model = reinterpret_cast<ANPDrawingModel>(value);
+ switch (model) {
+ case kBitmap_ANPDrawingModel:
+ m_window->setDrawingModel(model);
+ error = NPERR_NO_ERROR;
+ break;
+ default:
+ break;
+ }
+ }
+ default:
+ break;
+ }
+ return error;
+}
+
+void PluginView::invalidateRect(const IntRect& r)
+{
+ m_window->inval(r, true);
+}
+
+void PluginView::invalidateRect(NPRect* rect)
+{
+ IntRect r;
+
+ if (rect) {
+ r = IntRect(rect->left, rect->top,
+ rect->right - rect->left, rect->bottom - rect->top);
+ } else {
+ r = IntRect(0, 0, m_npWindow.width, m_npWindow.height);
+ }
+
+ m_window->inval(r, true);
+// android::WebViewCore::getWebViewCore(parent())->contentInvalidate(r);
+}
+
+void PluginView::invalidateRegion(NPRegion region)
+{
+ // we don't support/define regions (yet), so do nothing
+}
+
+void PluginView::forceRedraw()
+{
+ this->invalidateRect(0);
+}
+
+void PluginView::setFocus()
+{
+ Widget::setFocus();
+// SkDebugf("------------- setFocus %p\n", this);
+}
+
+void PluginView::show()
+{
+ setSelfVisible(true);
+ Widget::show();
+}
+
+void PluginView::hide()
+{
+ setSelfVisible(false);
+ Widget::hide();
+}
+
+void PluginView::paintMissingPluginIcon(GraphicsContext* context,
+ const IntRect& rect)
+{
+ static RefPtr<Image> gNullPluginImage;
+ if (!gNullPluginImage) {
+ gNullPluginImage = Image::loadPlatformResource("nullplugin");
+ }
+ Image* image = gNullPluginImage.get();
+
+ IntRect imageRect(frameRect().x(), frameRect().y(),
+ image->width(), image->height());
+
+ int xOffset = (frameRect().width() - imageRect.width()) / 2;
+ int yOffset = (frameRect().height() - imageRect.height()) / 2;
+
+ imageRect.move(xOffset, yOffset);
+
+ if (!rect.intersects(imageRect))
+ return;
+
+ context->drawImage(image, imageRect.location());
+}
+
+void PluginView::paint(GraphicsContext* context, const IntRect& rect)
+{
+ if (!m_isStarted) {
+ // Draw the "missing plugin" image
+ paintMissingPluginIcon(context, rect);
+ return;
+ }
+
+ IntRect frame = frameRect();
+ if (!frame.width() || !frame.height()) {
+ return;
+ }
+
+ m_window->inval(rect, false);
+ m_window->draw(android_gc2canvas(context));
+}
+
+// new as of SVN 38068, Nov 5 2008
+void PluginView::updatePluginWidget() const
+{
+ notImplemented();
+}
+
+// new as of SVN 38068, Nov 5 2008
+void PluginView::setParentVisible(bool) {
+ notImplemented();
+}
+
+} // namespace WebCore
+