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 "android_graphics.h" 46 #include <JNIUtility.h> 47 48 //#define PLUGIN_DEBUG_LOCAL // controls the printing of log messages 49 #define DEBUG_EVENTS 0 // logs event contents, return value, and processing time 50 #define DEBUG_VISIBLE_RECTS 0 // temporary debug printfs and fixes 51 52 #define MAX( a, b ) ( ((a) > (b)) ? (a) : (b) ) 53 54 // this include statement must follow the declaration of PLUGIN_DEBUG_LOCAL 55 #include "PluginDebugAndroid.h" 56 57 PluginWidgetAndroid::PluginWidgetAndroid(WebCore::PluginView* view) 58 : m_pluginView(view) { 59 m_flipPixelRef = NULL; 60 m_core = NULL; 61 m_drawingModel = kBitmap_ANPDrawingModel; 62 m_eventFlags = 0; 63 m_pluginWindow = NULL; 64 m_requestedVisibleRectCount = 0; 65 m_requestedVisibleRect.setEmpty(); 66 m_visibleDocRect.setEmpty(); 67 m_pluginBounds.setEmpty(); 68 m_hasFocus = false; 69 m_isFullScreen = false; 70 m_visible = false; 71 m_cachedZoomLevel = 0; 72 m_embeddedView = NULL; 73 m_embeddedViewAttached = false; 74 m_acceptEvents = false; 75 m_isSurfaceClippedOut = false; 76 m_layer = 0; 77 m_powerState = kDefault_ANPPowerState; 78 m_fullScreenOrientation = -1; 79 m_drawEventDelayed = false; 80 } 81 82 PluginWidgetAndroid::~PluginWidgetAndroid() { 83 PLUGIN_LOG("%p Deleting Plugin", m_pluginView->instance()); 84 m_acceptEvents = false; 85 if (m_core) { 86 setPowerState(kDefault_ANPPowerState); 87 m_core->removePlugin(this); 88 if (m_isFullScreen) { 89 exitFullScreen(true); 90 } 91 if (m_embeddedView) { 92 m_core->destroySurface(m_embeddedView); 93 } 94 } 95 96 // cleanup any remaining JNI References 97 JNIEnv* env = JSC::Bindings::getJNIEnv(); 98 if (m_embeddedView) { 99 env->DeleteGlobalRef(m_embeddedView); 100 } 101 102 SkSafeUnref(m_flipPixelRef); 103 SkSafeUnref(m_layer); 104 } 105 106 void PluginWidgetAndroid::init(android::WebViewCore* core) { 107 m_core = core; 108 m_core->addPlugin(this); 109 m_acceptEvents = true; 110 PLUGIN_LOG("%p Initialized Plugin", m_pluginView->instance()); 111 } 112 113 static SkBitmap::Config computeConfig(bool isTransparent) { 114 return isTransparent ? SkBitmap::kARGB_8888_Config 115 : SkBitmap::kRGB_565_Config; 116 } 117 118 void PluginWidgetAndroid::setWindow(NPWindow* window, bool isTransparent) { 119 120 // store the reference locally for easy lookup 121 m_pluginWindow = window; 122 123 // make a copy of the previous bounds 124 SkIRect oldPluginBounds = m_pluginBounds; 125 126 // keep a local copy of the plugin bounds because the m_pluginWindow pointer 127 // gets updated values prior to this method being called 128 m_pluginBounds.set(m_pluginWindow->x, m_pluginWindow->y, 129 m_pluginWindow->x + m_pluginWindow->width, 130 m_pluginWindow->y + m_pluginWindow->height); 131 132 PLUGIN_LOG("%p PluginBounds (%d,%d,%d,%d)", m_pluginView->instance(), 133 m_pluginBounds.fLeft, m_pluginBounds.fTop, 134 m_pluginBounds.fRight, m_pluginBounds.fBottom); 135 136 const bool boundsChanged = m_pluginBounds != oldPluginBounds; 137 138 //TODO hack to ensure that we grab the most recent screen dimensions and scale 139 ANPRectI screenCoords; 140 m_core->getVisibleScreen(screenCoords); 141 float scale = m_core->scale(); 142 bool scaleChanged = m_cachedZoomLevel != scale; 143 setVisibleScreen(screenCoords, scale); 144 145 // if the scale changed then setVisibleScreen will call this function and 146 // this call will potentially fire a duplicate draw event 147 if (!scaleChanged) { 148 sendSizeAndVisibilityEvents(boundsChanged); 149 } 150 layoutSurface(boundsChanged); 151 152 if (m_drawingModel != kSurface_ANPDrawingModel) { 153 SkSafeUnref(m_flipPixelRef); 154 m_flipPixelRef = new SkFlipPixelRef(computeConfig(isTransparent), 155 window->width, window->height); 156 } 157 } 158 159 bool PluginWidgetAndroid::setDrawingModel(ANPDrawingModel model) { 160 161 if (model == kOpenGL_ANPDrawingModel && m_layer == 0) { 162 jobject webview = m_core->getWebViewJavaObject(); 163 AutoJObject webViewCore = m_core->getJavaObject(); 164 m_layer = new WebCore::MediaLayer(webview, webViewCore.get()); 165 } 166 else if (model != kOpenGL_ANPDrawingModel && m_layer != 0) { 167 m_layer->unref(); 168 m_layer = 0; 169 } 170 171 if (m_drawingModel != model) { 172 // Trigger layer computation in RenderLayerCompositor 173 m_pluginView->getElement()->setNeedsStyleRecalc(SyntheticStyleChange); 174 } 175 176 m_drawingModel = model; 177 return true; 178 } 179 180 void PluginWidgetAndroid::checkSurfaceReady() { 181 if(!m_drawEventDelayed) 182 return; 183 184 m_drawEventDelayed = false; 185 sendSizeAndVisibilityEvents(true); 186 } 187 188 // returned rect is in the page coordinate 189 bool PluginWidgetAndroid::isDirty(SkIRect* rect) const { 190 // nothing to report if we haven't had setWindow() called yet 191 if (NULL == m_flipPixelRef) { 192 return false; 193 } 194 195 const SkRegion& dirty = m_flipPixelRef->dirtyRgn(); 196 if (dirty.isEmpty()) { 197 return false; 198 } else { 199 if (rect) { 200 *rect = dirty.getBounds(); 201 rect->offset(m_pluginWindow->x, m_pluginWindow->y); 202 } 203 return true; 204 } 205 } 206 207 void PluginWidgetAndroid::inval(const WebCore::IntRect& rect, 208 bool signalRedraw) { 209 // nothing to do if we haven't had setWindow() called yet. m_flipPixelRef 210 // will also be null if this is a Surface model. 211 if (NULL == m_flipPixelRef) { 212 return; 213 } 214 215 m_flipPixelRef->inval(rect); 216 217 if (signalRedraw && m_flipPixelRef->isDirty()) { 218 m_core->invalPlugin(this); 219 } 220 } 221 222 void PluginWidgetAndroid::viewInvalidate() { 223 WebCore::IntRect rect(m_pluginBounds.fLeft, m_pluginBounds.fTop, 224 m_pluginBounds.width(), m_pluginBounds.height()); 225 m_core->viewInvalidate(rect); 226 } 227 228 void PluginWidgetAndroid::draw(SkCanvas* canvas) { 229 if (NULL == m_flipPixelRef || !m_flipPixelRef->isDirty()) { 230 return; 231 } 232 233 SkAutoFlipUpdate update(m_flipPixelRef); 234 const SkBitmap& bitmap = update.bitmap(); 235 const SkRegion& dirty = update.dirty(); 236 237 ANPEvent event; 238 SkANP::InitEvent(&event, kDraw_ANPEventType); 239 240 event.data.draw.model = m_drawingModel; 241 SkANP::SetRect(&event.data.draw.clip, dirty.getBounds()); 242 243 switch (m_drawingModel) { 244 case kBitmap_ANPDrawingModel: { 245 WebCore::PluginPackage* pkg = m_pluginView->plugin(); 246 NPP instance = m_pluginView->instance(); 247 248 if (SkANP::SetBitmap(&event.data.draw.data.bitmap, 249 bitmap) && 250 pkg->pluginFuncs()->event(instance, &event)) { 251 252 if (canvas && m_pluginWindow) { 253 SkBitmap bm(bitmap); 254 bm.setPixelRef(m_flipPixelRef); 255 canvas->drawBitmap(bm, 0, 0); 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