| /* |
| * Copyright (C) 2011 Research In Motion Limited. All rights reserved. |
| * |
| * This library is free software; you can redistribute it and/or |
| * modify it under the terms of the GNU Lesser General Public |
| * License as published by the Free Software Foundation; either |
| * version 2 of the License, or (at your option) any later version. |
| * |
| * This library is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| * Lesser General Public License for more details. |
| * |
| * You should have received a copy of the GNU Lesser General Public |
| * License along with this library; if not, write to the Free Software |
| * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
| */ |
| |
| #include "config.h" |
| #include "PluginViewPrivateBlackBerry.h" |
| |
| #include "FrameView.h" |
| #include "HostWindow.h" |
| #if USE(ACCELERATED_COMPOSITING) |
| #include "PluginLayerWebKitThread.h" |
| #endif |
| #include "NPCallbacksBlackBerry.h" |
| #include <BlackBerryPlatformExecutableMessage.h> |
| #include <BlackBerryPlatformMessageClient.h> |
| #include <wtf/MainThread.h> |
| |
| static unsigned s_counter = 0; |
| |
| namespace WebCore { |
| |
| PluginViewPrivate::PluginViewPrivate(PluginView* view) |
| : m_view(view) |
| , m_pluginBufferType(BlackBerry::Platform::Graphics::PluginBufferWithAlpha) |
| , m_pluginFrontBuffer(0) |
| , m_idlePrevented(false) |
| , m_hasPendingGeometryChange(true) |
| , m_sentOnLoad(false) |
| , m_isFullScreen(false) |
| , m_isFocused(false) |
| , m_orientationLocked(false) |
| , m_isBackgroundPlaying(false) |
| { |
| m_pluginBuffers[0] = 0; |
| m_pluginBuffers[1] = 0; |
| |
| pthread_mutexattr_t mutexAttributes; |
| pthread_mutexattr_init(&mutexAttributes); |
| pthread_mutexattr_settype(&mutexAttributes, PTHREAD_MUTEX_RECURSIVE); |
| |
| pthread_mutex_init(&m_backBufferMutex, &mutexAttributes); |
| pthread_rwlock_init(&m_frontBufferRwLock, 0); |
| |
| pthread_mutexattr_destroy(&mutexAttributes); |
| |
| char uniqueId[50]; |
| snprintf(uniqueId, sizeof(uniqueId), "PluginViewBB-%08x%08x-", s_counter++, (int)this); |
| m_pluginUniquePrefix = uniqueId; |
| } |
| |
| PluginViewPrivate::~PluginViewPrivate() |
| { |
| #if USE(ACCELERATED_COMPOSITING) |
| if (m_platformLayer) |
| static_cast<PluginLayerWebKitThread*>(m_platformLayer.get())->setPluginView(0); |
| #endif |
| |
| destroyBuffers(); |
| |
| pthread_mutex_destroy(&m_backBufferMutex); |
| pthread_rwlock_destroy(&m_frontBufferRwLock); |
| } |
| |
| BlackBerry::Platform::Graphics::BufferType PluginViewPrivate::toBufferType(NPSurfaceFormat format) |
| { |
| switch (format) { |
| case FORMAT_RGB_565: |
| return BlackBerry::Platform::Graphics::PluginBuffer; |
| case FORMAT_RGBA_8888: |
| default: |
| return BlackBerry::Platform::Graphics::PluginBufferWithAlpha; |
| } |
| } |
| |
| void PluginViewPrivate::setZoomFactor(float zoomFactor) |
| { |
| if (((NPSetWindowCallbackStruct*)m_view->m_npWindow.ws_info)->zoomFactor != zoomFactor) |
| m_hasPendingGeometryChange = true; |
| |
| ((NPSetWindowCallbackStruct*)m_view->m_npWindow.ws_info)->zoomFactor = zoomFactor; |
| } |
| |
| void PluginViewPrivate::setVisibleRects(const NPRect rects[], int32_t count) |
| { |
| m_keepVisibleRect = IntRect(); |
| |
| if (!m_view->parent() || !count) |
| return; |
| |
| for (int i = 0; i < count; i++) { |
| IntRect addRect = IntRect(rects[i].left, rects[i].top, rects[i].right - rects[i].left, rects[i].bottom - rects[i].top); |
| m_keepVisibleRect.unite(addRect); |
| } |
| |
| // Don't cause a possible scroll if the result is an empty rectangle. |
| if (m_keepVisibleRect.isEmpty()) |
| return; |
| |
| // Adjust the rect to the parent window and then adjust for scrolling. |
| m_keepVisibleRect = m_view->convertToContainingWindow(m_keepVisibleRect); |
| FrameView* frameView = static_cast<FrameView*>(m_view->parent()); |
| m_keepVisibleRect.move(frameView->scrollPosition().x(), frameView->scrollPosition().y()); |
| |
| frameView->hostWindow()->platformPageClient()->ensureContentVisible(); |
| } |
| |
| void PluginViewPrivate::clearVisibleRects() |
| { |
| if (!m_keepVisibleRect.isEmpty()) |
| setVisibleRects(0, 0); |
| } |
| |
| void PluginViewPrivate::showKeyboard(bool value) |
| { |
| FrameView* frameView = static_cast<FrameView*>(m_view->parent()); |
| frameView->hostWindow()->platformPageClient()->showVirtualKeyboard(value); |
| } |
| |
| void PluginViewPrivate::requestFullScreen() |
| { |
| if (FrameView* frameView = static_cast<FrameView*>(m_view->parent())) |
| if (frameView->hostWindow()->platformPageClient()->shouldPluginEnterFullScreen(m_view, m_pluginUniquePrefix.c_str())) |
| m_view->handleFullScreenAllowedEvent(); |
| } |
| |
| void PluginViewPrivate::exitFullScreen() |
| { |
| m_view->handleFullScreenExitEvent(); |
| } |
| |
| void PluginViewPrivate::requestCenterFitZoom() |
| { |
| FrameView* frameView = static_cast<FrameView*>(m_view->parent()); |
| |
| if (!frameView) |
| return; |
| |
| frameView->hostWindow()->platformPageClient()->zoomToContentRect(m_view->m_windowRect); |
| } |
| |
| void PluginViewPrivate::lockOrientation(bool landscape) |
| { |
| FrameView* frameView = static_cast<FrameView*>(m_view->parent()); |
| |
| if (!frameView) |
| return; |
| |
| frameView->hostWindow()->platformPageClient()->lockOrientation(landscape); |
| m_orientationLocked = true; |
| } |
| |
| void PluginViewPrivate::unlockOrientation() |
| { |
| if (!m_orientationLocked) |
| return; |
| |
| FrameView* frameView = static_cast<FrameView*>(m_view->parent()); |
| |
| if (!frameView) |
| return; |
| |
| frameView->hostWindow()->platformPageClient()->unlockOrientation(); |
| m_orientationLocked = false; |
| } |
| |
| void PluginViewPrivate::preventIdle(bool preventIdle) |
| { |
| if (preventIdle == m_idlePrevented) |
| return; |
| |
| FrameView* frameView = static_cast<FrameView*>(m_view->parent()); |
| if (!frameView) |
| return; |
| |
| frameView->hostWindow()->platformPageClient()->setPreventsScreenDimming(preventIdle); |
| m_idlePrevented = preventIdle; |
| } |
| |
| void PluginViewPrivate::setHolePunch(int x, int y, int width, int height) |
| { |
| if (width > 0 && height > 0) |
| m_holePunchRect = IntRect(x, y, width, height); |
| else |
| m_holePunchRect = IntRect(); |
| |
| // Clip the hole punch rectangle in case a plugin is 'overzealous', or |
| // does not clean up the hole punch rectangle correctly when exiting |
| // fullscreen (will mask bugs in the plugin). |
| m_holePunchRect.intersect(IntRect(IntPoint(0, 0), m_view->frameRect().size())); |
| |
| #if USE(ACCELERATED_COMPOSITING) |
| if (m_platformLayer) { |
| IntRect rect = m_holePunchRect; |
| |
| // Translate from plugin coordinates to contents coordinates. |
| if (!m_holePunchRect.isEmpty()) |
| rect.move(m_view->frameRect().x(), m_view->frameRect().y()); |
| |
| OwnPtr<HolePunchData> hp = adoptPtr(new HolePunchData); |
| hp->x = m_holePunchRect.x(); |
| hp->y = m_holePunchRect.y(); |
| hp->w = m_holePunchRect.width(); |
| hp->h = m_holePunchRect.height(); |
| hp->layer = m_platformLayer; |
| |
| // Notify compositing layer and page client in order to be able to |
| // punch through composited and non-composited parts of the page. |
| callOnMainThread(npSetHolePunchHandler, hp.leakPtr()); // npSetHolePunchHandler() takes ownership of hp. |
| } |
| #endif |
| } |
| |
| NPSurface PluginViewPrivate::lockBackBuffer() |
| { |
| pthread_mutex_lock(&m_backBufferMutex); |
| BlackBerry::Platform::Graphics::Buffer* buffer = m_pluginBuffers[(m_pluginFrontBuffer + 1) % PLUGIN_BUFFERS]; |
| |
| if (!buffer || !BlackBerry::Platform::Graphics::platformBufferHandle(buffer)) { |
| unlockBackBuffer(); |
| return 0; |
| } |
| |
| return BlackBerry::Platform::Graphics::platformBufferHandle(buffer); |
| } |
| |
| void PluginViewPrivate::unlockBackBuffer() |
| { |
| pthread_mutex_unlock(&m_backBufferMutex); |
| } |
| |
| BlackBerry::Platform::Graphics::Buffer* PluginViewPrivate::lockReadFrontBufferInternal() |
| { |
| pthread_rwlock_rdlock(&m_frontBufferRwLock); |
| return m_pluginBuffers[m_pluginFrontBuffer]; |
| } |
| |
| NPSurface PluginViewPrivate::lockReadFrontBuffer() |
| { |
| BlackBerry::Platform::Graphics::Buffer* buffer = lockReadFrontBufferInternal(); |
| |
| if (!buffer || !BlackBerry::Platform::Graphics::platformBufferHandle(buffer)) { |
| unlockReadFrontBuffer(); |
| return 0; |
| } |
| |
| return BlackBerry::Platform::Graphics::platformBufferHandle(buffer); |
| } |
| |
| void PluginViewPrivate::unlockReadFrontBuffer() |
| { |
| pthread_rwlock_unlock(&m_frontBufferRwLock); |
| } |
| |
| void PluginViewPrivate::swapBuffers() |
| { |
| PthreadMutexLocker backLock(&m_backBufferMutex); |
| PthreadWriteLocker frontLock(&m_frontBufferRwLock); |
| m_pluginFrontBuffer = (m_pluginFrontBuffer + 1) % 2; |
| } |
| |
| bool PluginViewPrivate::createBuffers(NPSurfaceFormat format, int width, int height) |
| { |
| bool success = true; |
| |
| PthreadMutexLocker backLock(&m_backBufferMutex); |
| PthreadWriteLocker frontLock(&m_frontBufferRwLock); |
| |
| bool didDestroyBuffers = false; |
| for (int i = 0; i < PLUGIN_BUFFERS; i++) { |
| if (m_pluginBuffers[i]) { |
| didDestroyBuffers = true; |
| BlackBerry::Platform::Graphics::destroyBuffer(m_pluginBuffers[i]); |
| m_pluginBuffers[i] = 0; |
| } |
| |
| if (width <= 0 || height <= 0) |
| success = true; |
| else { |
| m_pluginBuffers[i] = BlackBerry::Platform::Graphics::createBuffer( |
| BlackBerry::Platform::IntSize(width, height), |
| toBufferType(format)); |
| |
| if (!m_pluginBuffers[i]) |
| success = false; |
| } |
| } |
| |
| if (success) { |
| m_pluginBufferSize = IntSize(width, height); |
| m_pluginBufferType = toBufferType(format); |
| |
| if (didDestroyBuffers) { |
| BlackBerry::Platform::userInterfaceThreadMessageClient()->dispatchSyncMessage( |
| BlackBerry::Platform::createFunctionCallMessage(&BlackBerry::Platform::Graphics::collectThreadSpecificGarbage)); |
| } |
| } else { |
| m_pluginBufferSize = IntSize(); |
| m_pluginBufferType = BlackBerry::Platform::Graphics::PluginBufferWithAlpha; |
| destroyBuffers(); |
| } |
| |
| return success; |
| } |
| |
| bool PluginViewPrivate::resizeBuffers(NPSurfaceFormat format, int width, int height) |
| { |
| bool success = true; |
| |
| // If there is no buffer created, then try to create it. |
| if (!m_pluginBufferSize.width() || !m_pluginBufferSize.height()) |
| return createBuffers(format, width, height); |
| |
| if (!width || !height) |
| return destroyBuffers(); |
| |
| PthreadMutexLocker backLock(&m_backBufferMutex); |
| PthreadWriteLocker frontLock(&m_frontBufferRwLock); |
| |
| for (int i = 0; i < PLUGIN_BUFFERS && success; i++) { |
| success &= BlackBerry::Platform::Graphics::reallocBuffer(m_pluginBuffers[i], |
| BlackBerry::Platform::IntSize(width, height), |
| toBufferType(format)); |
| } |
| |
| if (success) { |
| m_pluginBufferSize = IntSize(width, height); |
| m_pluginBufferType = toBufferType(format); |
| return true; |
| } |
| |
| // Attempt to undo if we failed to get the new size/format. We can't guarantee |
| // we will get it back though. |
| if (!m_pluginBufferSize.width() || !m_pluginBufferSize.height()) { |
| destroyBuffers(); |
| return false; |
| } |
| |
| bool undone = true; |
| for (int i = 0; i < PLUGIN_BUFFERS; i++) { |
| undone &= BlackBerry::Platform::Graphics::reallocBuffer(m_pluginBuffers[i], |
| m_pluginBufferSize, m_pluginBufferType); |
| } |
| |
| // If we fail to undo, delete the buffers altogether. |
| if (!undone) |
| destroyBuffers(); |
| |
| return false; |
| } |
| |
| bool PluginViewPrivate::destroyBuffers() |
| { |
| PthreadMutexLocker backLock(&m_backBufferMutex); |
| PthreadWriteLocker frontLock(&m_frontBufferRwLock); |
| |
| bool didDestroyBuffers = false; |
| for (int i = 0; i < PLUGIN_BUFFERS; i++) { |
| if (m_pluginBuffers[i]) { |
| didDestroyBuffers = true; |
| BlackBerry::Platform::Graphics::destroyBuffer(m_pluginBuffers[i]); |
| m_pluginBuffers[i] = 0; |
| } |
| } |
| m_pluginBufferSize = IntSize(); |
| |
| if (didDestroyBuffers) { |
| BlackBerry::Platform::userInterfaceThreadMessageClient()->dispatchSyncMessage( |
| BlackBerry::Platform::createFunctionCallMessage(&BlackBerry::Platform::Graphics::collectThreadSpecificGarbage)); |
| } |
| |
| return true; |
| } |
| |
| } // namespace WebCore |
| |
| |