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 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 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 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 112 static SkBitmap::Config computeConfig(bool isTransparent) { 113 return isTransparent ? SkBitmap::kARGB_8888_Config 114 : SkBitmap::kRGB_565_Config; 115 } 116 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 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 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 188 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 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 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 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 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 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 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 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 390 bool PluginWidgetAndroid::isAcceptingEvent(ANPEventFlag flag) { 391 return m_eventFlags & flag; 392 } 393 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 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 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 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 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 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 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 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 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 701 void PluginWidgetAndroid::requestCenterFitZoom() { 702 m_core->centerFitRect(m_pluginWindow->x, m_pluginWindow->y, 703 m_pluginWindow->width, m_pluginWindow->height); 704 } 705 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