1/* 2 * Copyright (C) 2011 Research In Motion Limited. All rights reserved. 3 * 4 * This library is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU Lesser General Public 6 * License as published by the Free Software Foundation; either 7 * version 2 of the License, or (at your option) any later version. 8 * 9 * This library is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 * Lesser General Public License for more details. 13 * 14 * You should have received a copy of the GNU Lesser General Public 15 * License along with this library; if not, write to the Free Software 16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 17 */ 18 19#include "config.h" 20#include "PluginViewPrivateBlackBerry.h" 21 22#include "FrameView.h" 23#include "HostWindow.h" 24#if USE(ACCELERATED_COMPOSITING) 25#include "PluginLayerWebKitThread.h" 26#endif 27#include "NPCallbacksBlackBerry.h" 28#include <BlackBerryPlatformExecutableMessage.h> 29#include <BlackBerryPlatformMessageClient.h> 30#include <wtf/MainThread.h> 31 32static unsigned s_counter = 0; 33 34namespace WebCore { 35 36PluginViewPrivate::PluginViewPrivate(PluginView* view) 37 : m_view(view) 38 , m_pluginBufferType(BlackBerry::Platform::Graphics::PluginBufferWithAlpha) 39 , m_pluginFrontBuffer(0) 40 , m_idlePrevented(false) 41 , m_hasPendingGeometryChange(true) 42 , m_sentOnLoad(false) 43 , m_isFullScreen(false) 44 , m_isFocused(false) 45 , m_orientationLocked(false) 46 , m_isBackgroundPlaying(false) 47{ 48 m_pluginBuffers[0] = 0; 49 m_pluginBuffers[1] = 0; 50 51 pthread_mutexattr_t mutexAttributes; 52 pthread_mutexattr_init(&mutexAttributes); 53 pthread_mutexattr_settype(&mutexAttributes, PTHREAD_MUTEX_RECURSIVE); 54 55 pthread_mutex_init(&m_backBufferMutex, &mutexAttributes); 56 pthread_rwlock_init(&m_frontBufferRwLock, 0); 57 58 pthread_mutexattr_destroy(&mutexAttributes); 59 60 char uniqueId[50]; 61 snprintf(uniqueId, sizeof(uniqueId), "PluginViewBB-%08x%08x-", s_counter++, (int)this); 62 m_pluginUniquePrefix = uniqueId; 63} 64 65PluginViewPrivate::~PluginViewPrivate() 66{ 67#if USE(ACCELERATED_COMPOSITING) 68 if (m_platformLayer) 69 static_cast<PluginLayerWebKitThread*>(m_platformLayer.get())->setPluginView(0); 70#endif 71 72 destroyBuffers(); 73 74 pthread_mutex_destroy(&m_backBufferMutex); 75 pthread_rwlock_destroy(&m_frontBufferRwLock); 76} 77 78BlackBerry::Platform::Graphics::BufferType PluginViewPrivate::toBufferType(NPSurfaceFormat format) 79{ 80 switch (format) { 81 case FORMAT_RGB_565: 82 return BlackBerry::Platform::Graphics::PluginBuffer; 83 case FORMAT_RGBA_8888: 84 default: 85 return BlackBerry::Platform::Graphics::PluginBufferWithAlpha; 86 } 87} 88 89void PluginViewPrivate::setZoomFactor(float zoomFactor) 90{ 91 if (((NPSetWindowCallbackStruct*)m_view->m_npWindow.ws_info)->zoomFactor != zoomFactor) 92 m_hasPendingGeometryChange = true; 93 94 ((NPSetWindowCallbackStruct*)m_view->m_npWindow.ws_info)->zoomFactor = zoomFactor; 95} 96 97void PluginViewPrivate::setVisibleRects(const NPRect rects[], int32_t count) 98{ 99 m_keepVisibleRect = IntRect(); 100 101 if (!m_view->parent() || !count) 102 return; 103 104 for (int i = 0; i < count; i++) { 105 IntRect addRect = IntRect(rects[i].left, rects[i].top, rects[i].right - rects[i].left, rects[i].bottom - rects[i].top); 106 m_keepVisibleRect.unite(addRect); 107 } 108 109 // Don't cause a possible scroll if the result is an empty rectangle. 110 if (m_keepVisibleRect.isEmpty()) 111 return; 112 113 // Adjust the rect to the parent window and then adjust for scrolling. 114 m_keepVisibleRect = m_view->convertToContainingWindow(m_keepVisibleRect); 115 FrameView* frameView = toFrameView(m_view->parent()); 116 m_keepVisibleRect.move(frameView->scrollPosition().x(), frameView->scrollPosition().y()); 117 118 frameView->hostWindow()->platformPageClient()->ensureContentVisible(); 119} 120 121void PluginViewPrivate::clearVisibleRects() 122{ 123 if (!m_keepVisibleRect.isEmpty()) 124 setVisibleRects(0, 0); 125} 126 127void PluginViewPrivate::showKeyboard(bool value) 128{ 129 FrameView* frameView = toFrameView(m_view->parent()); 130 frameView->hostWindow()->platformPageClient()->showVirtualKeyboard(value); 131} 132 133void PluginViewPrivate::requestFullScreen() 134{ 135 if (FrameView* frameView = toFrameView(m_view->parent())) 136 if (frameView->hostWindow()->platformPageClient()->shouldPluginEnterFullScreen(m_view, m_pluginUniquePrefix.c_str())) 137 m_view->handleFullScreenAllowedEvent(); 138} 139 140void PluginViewPrivate::exitFullScreen() 141{ 142 m_view->handleFullScreenExitEvent(); 143} 144 145void PluginViewPrivate::requestCenterFitZoom() 146{ 147 FrameView* frameView = toFrameView(m_view->parent()); 148 149 if (!frameView) 150 return; 151 152 frameView->hostWindow()->platformPageClient()->zoomToContentRect(m_view->m_windowRect); 153} 154 155void PluginViewPrivate::lockOrientation(bool landscape) 156{ 157 FrameView* frameView = toFrameView(m_view->parent()); 158 159 if (!frameView) 160 return; 161 162 frameView->hostWindow()->platformPageClient()->lockOrientation(landscape); 163 m_orientationLocked = true; 164} 165 166void PluginViewPrivate::unlockOrientation() 167{ 168 if (!m_orientationLocked) 169 return; 170 171 FrameView* frameView = toFrameView(m_view->parent()); 172 173 if (!frameView) 174 return; 175 176 frameView->hostWindow()->platformPageClient()->unlockOrientation(); 177 m_orientationLocked = false; 178} 179 180void PluginViewPrivate::preventIdle(bool preventIdle) 181{ 182 if (preventIdle == m_idlePrevented) 183 return; 184 185 FrameView* frameView = toFrameView(m_view->parent()); 186 if (!frameView) 187 return; 188 189 frameView->hostWindow()->platformPageClient()->setPreventsScreenDimming(preventIdle); 190 m_idlePrevented = preventIdle; 191} 192 193void PluginViewPrivate::setHolePunch(int x, int y, int width, int height) 194{ 195 if (width > 0 && height > 0) 196 m_holePunchRect = IntRect(x, y, width, height); 197 else 198 m_holePunchRect = IntRect(); 199 200 // Clip the hole punch rectangle in case a plugin is 'overzealous', or 201 // does not clean up the hole punch rectangle correctly when exiting 202 // fullscreen (will mask bugs in the plugin). 203 m_holePunchRect.intersect(IntRect(IntPoint(0, 0), m_view->frameRect().size())); 204 205#if USE(ACCELERATED_COMPOSITING) 206 if (m_platformLayer) { 207 IntRect rect = m_holePunchRect; 208 209 // Translate from plugin coordinates to contents coordinates. 210 if (!m_holePunchRect.isEmpty()) 211 rect.move(m_view->frameRect().x(), m_view->frameRect().y()); 212 213 OwnPtr<HolePunchData> hp = adoptPtr(new HolePunchData); 214 hp->x = m_holePunchRect.x(); 215 hp->y = m_holePunchRect.y(); 216 hp->w = m_holePunchRect.width(); 217 hp->h = m_holePunchRect.height(); 218 hp->layer = m_platformLayer; 219 220 // Notify compositing layer and page client in order to be able to 221 // punch through composited and non-composited parts of the page. 222 callOnMainThread(npSetHolePunchHandler, hp.leakPtr()); // npSetHolePunchHandler() takes ownership of hp. 223 } 224#endif 225} 226 227NPSurface PluginViewPrivate::lockBackBuffer() 228{ 229 pthread_mutex_lock(&m_backBufferMutex); 230 BlackBerry::Platform::Graphics::Buffer* buffer = m_pluginBuffers[(m_pluginFrontBuffer + 1) % PLUGIN_BUFFERS]; 231 232 if (!buffer || !BlackBerry::Platform::Graphics::platformBufferHandle(buffer)) { 233 unlockBackBuffer(); 234 return 0; 235 } 236 237 return BlackBerry::Platform::Graphics::platformBufferHandle(buffer); 238} 239 240void PluginViewPrivate::unlockBackBuffer() 241{ 242 pthread_mutex_unlock(&m_backBufferMutex); 243} 244 245BlackBerry::Platform::Graphics::Buffer* PluginViewPrivate::lockReadFrontBufferInternal() 246{ 247 pthread_rwlock_rdlock(&m_frontBufferRwLock); 248 return m_pluginBuffers[m_pluginFrontBuffer]; 249} 250 251NPSurface PluginViewPrivate::lockReadFrontBuffer() 252{ 253 BlackBerry::Platform::Graphics::Buffer* buffer = lockReadFrontBufferInternal(); 254 255 if (!buffer || !BlackBerry::Platform::Graphics::platformBufferHandle(buffer)) { 256 unlockReadFrontBuffer(); 257 return 0; 258 } 259 260 return BlackBerry::Platform::Graphics::platformBufferHandle(buffer); 261} 262 263void PluginViewPrivate::unlockReadFrontBuffer() 264{ 265 pthread_rwlock_unlock(&m_frontBufferRwLock); 266} 267 268void PluginViewPrivate::swapBuffers() 269{ 270 PthreadMutexLocker backLock(&m_backBufferMutex); 271 PthreadWriteLocker frontLock(&m_frontBufferRwLock); 272 m_pluginFrontBuffer = (m_pluginFrontBuffer + 1) % 2; 273} 274 275bool PluginViewPrivate::createBuffers(NPSurfaceFormat format, int width, int height) 276{ 277 bool success = true; 278 279 PthreadMutexLocker backLock(&m_backBufferMutex); 280 PthreadWriteLocker frontLock(&m_frontBufferRwLock); 281 282 bool didDestroyBuffers = false; 283 for (int i = 0; i < PLUGIN_BUFFERS; i++) { 284 if (m_pluginBuffers[i]) { 285 didDestroyBuffers = true; 286 BlackBerry::Platform::Graphics::destroyBuffer(m_pluginBuffers[i]); 287 m_pluginBuffers[i] = 0; 288 } 289 290 if (width <= 0 || height <= 0) 291 success = true; 292 else { 293 m_pluginBuffers[i] = BlackBerry::Platform::Graphics::createBuffer( 294 BlackBerry::Platform::IntSize(width, height), 295 toBufferType(format)); 296 297 if (!m_pluginBuffers[i]) 298 success = false; 299 } 300 } 301 302 if (success) { 303 m_pluginBufferSize = IntSize(width, height); 304 m_pluginBufferType = toBufferType(format); 305 306 if (didDestroyBuffers) { 307 BlackBerry::Platform::userInterfaceThreadMessageClient()->dispatchSyncMessage( 308 BlackBerry::Platform::createFunctionCallMessage(&BlackBerry::Platform::Graphics::collectThreadSpecificGarbage)); 309 } 310 } else { 311 m_pluginBufferSize = IntSize(); 312 m_pluginBufferType = BlackBerry::Platform::Graphics::PluginBufferWithAlpha; 313 destroyBuffers(); 314 } 315 316 return success; 317} 318 319bool PluginViewPrivate::resizeBuffers(NPSurfaceFormat format, int width, int height) 320{ 321 bool success = true; 322 323 // If there is no buffer created, then try to create it. 324 if (!m_pluginBufferSize.width() || !m_pluginBufferSize.height()) 325 return createBuffers(format, width, height); 326 327 if (!width || !height) 328 return destroyBuffers(); 329 330 PthreadMutexLocker backLock(&m_backBufferMutex); 331 PthreadWriteLocker frontLock(&m_frontBufferRwLock); 332 333 for (int i = 0; i < PLUGIN_BUFFERS && success; i++) { 334 success &= BlackBerry::Platform::Graphics::reallocBuffer(m_pluginBuffers[i], 335 BlackBerry::Platform::IntSize(width, height), 336 toBufferType(format)); 337 } 338 339 if (success) { 340 m_pluginBufferSize = IntSize(width, height); 341 m_pluginBufferType = toBufferType(format); 342 return true; 343 } 344 345 // Attempt to undo if we failed to get the new size/format. We can't guarantee 346 // we will get it back though. 347 if (!m_pluginBufferSize.width() || !m_pluginBufferSize.height()) { 348 destroyBuffers(); 349 return false; 350 } 351 352 bool undone = true; 353 for (int i = 0; i < PLUGIN_BUFFERS; i++) { 354 undone &= BlackBerry::Platform::Graphics::reallocBuffer(m_pluginBuffers[i], 355 m_pluginBufferSize, m_pluginBufferType); 356 } 357 358 // If we fail to undo, delete the buffers altogether. 359 if (!undone) 360 destroyBuffers(); 361 362 return false; 363} 364 365bool PluginViewPrivate::destroyBuffers() 366{ 367 bool didDestroyBuffers = false; 368 369 { 370 PthreadMutexLocker backLock(&m_backBufferMutex); 371 PthreadWriteLocker frontLock(&m_frontBufferRwLock); 372 373 for (int i = 0; i < PLUGIN_BUFFERS; i++) { 374 if (m_pluginBuffers[i]) { 375 didDestroyBuffers = true; 376 BlackBerry::Platform::Graphics::destroyBuffer(m_pluginBuffers[i]); 377 m_pluginBuffers[i] = 0; 378 } 379 } 380 m_pluginBufferSize = IntSize(); 381 } 382 383 if (didDestroyBuffers) { 384 BlackBerry::Platform::userInterfaceThreadMessageClient()->dispatchSyncMessage( 385 BlackBerry::Platform::createFunctionCallMessage(&BlackBerry::Platform::Graphics::collectThreadSpecificGarbage)); 386 } 387 388 return true; 389} 390 391} // namespace WebCore 392 393 394