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 m_layer = new WebCore::MediaLayer(webview); 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(SkCanvas* canvas) { 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 (canvas && m_pluginWindow) { 252 SkBitmap bm(bitmap); 253 bm.setPixelRef(m_flipPixelRef); 254 canvas->drawBitmap(bm, 0, 0); 255 } 256 } 257 break; 258 } 259 default: 260 break; 261 } 262 } 263 264 void PluginWidgetAndroid::setSurfaceClip(const SkIRect& clip) { 265 266 if (m_drawingModel != kSurface_ANPDrawingModel) 267 return; 268 269 /* don't display surfaces that are either entirely clipped or only 1x1 in 270 size. It appears that when an element is absolutely positioned and has 271 been completely clipped in CSS that webkit still sends a clip of 1x1. 272 */ 273 bool clippedOut = (clip.width() <= 1 && clip.height() <= 1); 274 if(clippedOut != m_isSurfaceClippedOut) { 275 m_isSurfaceClippedOut = clippedOut; 276 layoutSurface(); 277 } 278 } 279 280 void PluginWidgetAndroid::layoutSurface(bool pluginBoundsChanged) { 281 282 if (m_drawingModel != kSurface_ANPDrawingModel) 283 return; 284 if (!m_pluginWindow) 285 return; 286 287 288 bool displayPlugin = m_pluginView->isVisible() && !m_isSurfaceClippedOut; 289 PLUGIN_LOG("%p DisplayPlugin[%d] visible=[%d] clipped=[%d]", 290 m_pluginView->instance(), displayPlugin, 291 m_pluginView->isVisible(), m_isSurfaceClippedOut); 292 293 // if the surface does not exist then create a new surface 294 if (!m_embeddedView && displayPlugin) { 295 296 WebCore::PluginPackage* pkg = m_pluginView->plugin(); 297 NPP instance = m_pluginView->instance(); 298 299 jobject pluginSurface; 300 pkg->pluginFuncs()->getvalue(instance, kJavaSurface_ANPGetValue, 301 static_cast<void*>(&pluginSurface)); 302 303 jobject tempObj = m_core->addSurface(pluginSurface, 304 m_pluginWindow->x, m_pluginWindow->y, 305 m_pluginWindow->width, m_pluginWindow->height); 306 307 if (tempObj) { 308 JNIEnv* env = JSC::Bindings::getJNIEnv(); 309 m_embeddedView = env->NewGlobalRef(tempObj); 310 m_embeddedViewAttached = true; 311 } 312 // if the view is unattached but visible then attach it 313 } else if (m_embeddedView && !m_embeddedViewAttached && displayPlugin && !m_isFullScreen) { 314 m_core->updateSurface(m_embeddedView, m_pluginWindow->x, m_pluginWindow->y, 315 m_pluginWindow->width, m_pluginWindow->height); 316 m_embeddedViewAttached = true; 317 // if the view is attached but invisible then remove it 318 } else if (m_embeddedView && m_embeddedViewAttached && !displayPlugin) { 319 m_core->destroySurface(m_embeddedView); 320 m_embeddedViewAttached = false; 321 // if the plugin's bounds have changed and it's visible then update it 322 } else if (pluginBoundsChanged && displayPlugin && !m_isFullScreen) { 323 m_core->updateSurface(m_embeddedView, m_pluginWindow->x, m_pluginWindow->y, 324 m_pluginWindow->width, m_pluginWindow->height); 325 326 } 327 } 328 329 int16_t PluginWidgetAndroid::sendEvent(const ANPEvent& evt) { 330 if (!m_acceptEvents) 331 return 0; 332 WebCore::PluginPackage* pkg = m_pluginView->plugin(); 333 NPP instance = m_pluginView->instance(); 334 // "missing" plugins won't have these 335 if (pkg && instance) { 336 337 // if the plugin is gaining focus then update our state now to allow 338 // the plugin's event handler to perform actions that require focus 339 if (evt.eventType == kLifecycle_ANPEventType && 340 evt.data.lifecycle.action == kGainFocus_ANPLifecycleAction) { 341 m_hasFocus = true; 342 } 343 344 #if DEBUG_EVENTS 345 SkMSec startTime = SkTime::GetMSecs(); 346 #endif 347 348 // make a localCopy since the actual plugin may not respect its constness, 349 // and so we don't want our caller to have its param modified 350 ANPEvent localCopy = evt; 351 int16_t result = pkg->pluginFuncs()->event(instance, &localCopy); 352 353 #if DEBUG_EVENTS 354 SkMSec endTime = SkTime::GetMSecs(); 355 PLUGIN_LOG_EVENT(instance, &evt, result, endTime - startTime); 356 #endif 357 358 // if the plugin is losing focus then delay the update of our state 359 // until after we notify the plugin and allow them to perform actions 360 // that may require focus 361 if (evt.eventType == kLifecycle_ANPEventType && 362 evt.data.lifecycle.action == kLoseFocus_ANPLifecycleAction) { 363 m_hasFocus = false; 364 } 365 366 return result; 367 } 368 return 0; 369 } 370 371 void PluginWidgetAndroid::updateEventFlags(ANPEventFlags flags) { 372 373 // if there are no differences then immediately return 374 if (m_eventFlags == flags) { 375 return; 376 } 377 378 Document* doc = m_pluginView->parentFrame()->document(); 379 #if ENABLE(TOUCH_EVENTS) 380 if((m_eventFlags ^ flags) & kTouch_ANPEventFlag) { 381 if (flags & kTouch_ANPEventFlag) 382 doc->addListenerTypeIfNeeded(eventNames().touchstartEvent); 383 } 384 #endif 385 386 m_eventFlags = flags; 387 } 388 389 bool PluginWidgetAndroid::isAcceptingEvent(ANPEventFlag flag) { 390 return m_eventFlags & flag; 391 } 392 393 void PluginWidgetAndroid::sendSizeAndVisibilityEvents(const bool updateDimensions) { 394 395 if (m_drawingModel == kOpenGL_ANPDrawingModel && 396 !m_layer->acquireNativeWindowForContent()) { 397 m_drawEventDelayed = true; 398 return; 399 } 400 401 // TODO update the bitmap size based on the zoom? (for kBitmap_ANPDrawingModel) 402 const float zoomLevel = m_core->scale(); 403 404 // notify the plugin of the new size 405 if (m_drawingModel == kOpenGL_ANPDrawingModel && updateDimensions && m_pluginWindow) { 406 PLUGIN_LOG("%s (%d,%d)[%f]", __FUNCTION__, m_pluginWindow->width, 407 m_pluginWindow->height, zoomLevel); 408 ANPEvent event; 409 SkANP::InitEvent(&event, kDraw_ANPEventType); 410 event.data.draw.model = kOpenGL_ANPDrawingModel; 411 event.data.draw.data.surface.width = m_pluginWindow->width * zoomLevel; 412 event.data.draw.data.surface.height = m_pluginWindow->height * zoomLevel; 413 sendEvent(event); 414 } 415 416 bool visible = SkIRect::Intersects(m_visibleDocRect, m_pluginBounds); 417 if(m_visible != visible) { 418 419 #if DEBUG_VISIBLE_RECTS 420 PLUGIN_LOG("%p changeVisiblity[%d] pluginBounds(%d,%d,%d,%d)", 421 m_pluginView->instance(), visible, 422 m_pluginBounds.fLeft, m_pluginBounds.fTop, 423 m_pluginBounds.fRight, m_pluginBounds.fBottom); 424 #endif 425 426 // change the visibility 427 m_visible = visible; 428 // send the event 429 ANPEvent event; 430 SkANP::InitEvent(&event, kLifecycle_ANPEventType); 431 event.data.lifecycle.action = visible ? kOnScreen_ANPLifecycleAction 432 : kOffScreen_ANPLifecycleAction; 433 sendEvent(event); 434 } 435 } 436 437 void PluginWidgetAndroid::setVisibleScreen(const ANPRectI& visibleDocRect, float zoom) { 438 #if DEBUG_VISIBLE_RECTS 439 PLUGIN_LOG("%s (%d,%d,%d,%d)[%f]", __FUNCTION__, visibleDocRect.left, 440 visibleDocRect.top, visibleDocRect.right, 441 visibleDocRect.bottom, zoom); 442 #endif 443 int oldScreenW = m_visibleDocRect.width(); 444 int oldScreenH = m_visibleDocRect.height(); 445 446 const bool zoomChanged = m_cachedZoomLevel != zoom; 447 448 // make local copies of the parameters 449 m_cachedZoomLevel = zoom; 450 m_visibleDocRect.set(visibleDocRect.left, 451 visibleDocRect.top, 452 visibleDocRect.right, 453 visibleDocRect.bottom); 454 455 int newScreenW = m_visibleDocRect.width(); 456 int newScreenH = m_visibleDocRect.height(); 457 458 // if the screen dimensions have changed by more than 5 pixels in either 459 // direction then recompute the plugin's visible rectangle 460 if (abs(oldScreenW - newScreenW) > 5 || abs(oldScreenH - newScreenH) > 5) { 461 PLUGIN_LOG("%s VisibleDoc old=[%d,%d] new=[%d,%d] ", __FUNCTION__, 462 oldScreenW, oldScreenH, newScreenW, newScreenH); 463 computeVisiblePluginRect(); 464 } 465 466 sendSizeAndVisibilityEvents(zoomChanged); 467 } 468 469 ANPRectI PluginWidgetAndroid::visibleRect() { 470 471 SkIRect visibleRect; 472 visibleRect.setEmpty(); 473 474 // compute the interesection of the visible screen and the plugin 475 bool visible = visibleRect.intersect(m_visibleDocRect, m_pluginBounds); 476 if (visible) { 477 // convert from absolute coordinates to the plugin's relative coordinates 478 visibleRect.offset(-m_pluginBounds.fLeft, -m_pluginBounds.fTop); 479 } 480 481 // convert from SkRect to ANPRect 482 ANPRectI result; 483 memcpy(&result, &visibleRect, sizeof(ANPRectI)); 484 return result; 485 } 486 487 void PluginWidgetAndroid::setVisibleRects(const ANPRectI rects[], int32_t count) { 488 #if DEBUG_VISIBLE_RECTS 489 PLUGIN_LOG("%s count=%d", __FUNCTION__, count); 490 #endif 491 // ensure the count does not exceed our allocated space 492 if (count > MAX_REQUESTED_RECTS) 493 count = MAX_REQUESTED_RECTS; 494 495 // store the values in member variables 496 m_requestedVisibleRectCount = count; 497 memcpy(m_requestedVisibleRects, rects, count * sizeof(rects[0])); 498 499 #if DEBUG_VISIBLE_RECTS // FIXME: this fixes bad data from the plugin 500 // take it out once plugin supplies better data 501 for (int index = 0; index < count; index++) { 502 PLUGIN_LOG("%s [%d](%d,%d,%d,%d)", __FUNCTION__, index, 503 m_requestedVisibleRects[index].left, 504 m_requestedVisibleRects[index].top, 505 m_requestedVisibleRects[index].right, 506 m_requestedVisibleRects[index].bottom); 507 if (m_requestedVisibleRects[index].left == 508 m_requestedVisibleRects[index].right) { 509 m_requestedVisibleRects[index].right += 1; 510 } 511 if (m_requestedVisibleRects[index].top == 512 m_requestedVisibleRects[index].bottom) { 513 m_requestedVisibleRects[index].bottom += 1; 514 } 515 } 516 #endif 517 computeVisiblePluginRect(); 518 } 519 520 void PluginWidgetAndroid::computeVisiblePluginRect() { 521 522 // ensure the visibleDocRect has been set (i.e. not equal to zero) 523 if (m_visibleDocRect.isEmpty() || !m_pluginWindow || m_requestedVisibleRectCount < 1) 524 return; 525 526 // create a rect that will contain as many of the rects that will fit on screen 527 SkIRect visibleRect; 528 visibleRect.setEmpty(); 529 530 for (int counter = 0; counter < m_requestedVisibleRectCount; counter++) { 531 532 ANPRectI* rect = &m_requestedVisibleRects[counter]; 533 534 // create skia rect for easier manipulation and convert it to page coordinates 535 SkIRect pluginRect; 536 pluginRect.set(rect->left, rect->top, rect->right, rect->bottom); 537 pluginRect.offset(m_pluginWindow->x, m_pluginWindow->y); 538 539 // ensure the rect falls within the plugin's bounds 540 if (!m_pluginBounds.contains(pluginRect)) { 541 #if DEBUG_VISIBLE_RECTS 542 PLUGIN_LOG("%s (%d,%d,%d,%d) !contain (%d,%d,%d,%d)", __FUNCTION__, 543 m_pluginBounds.fLeft, m_pluginBounds.fTop, 544 m_pluginBounds.fRight, m_pluginBounds.fBottom, 545 pluginRect.fLeft, pluginRect.fTop, 546 pluginRect.fRight, pluginRect.fBottom); 547 // assume that the desired outcome is to clamp to the container 548 if (pluginRect.intersect(m_pluginBounds)) { 549 visibleRect = pluginRect; 550 } 551 #endif 552 continue; 553 } 554 555 // combine this new rect with the higher priority rects 556 pluginRect.join(visibleRect); 557 558 // check to see if the new rect could be made to fit within the screen 559 // bounds. If this is the highest priority rect then attempt to center 560 // even if it doesn't fit on the screen. 561 if (counter > 0 && (m_visibleDocRect.width() < pluginRect.width() || 562 m_visibleDocRect.height() < pluginRect.height())) 563 break; 564 565 // set the new visible rect 566 visibleRect = pluginRect; 567 } 568 569 m_requestedVisibleRect = visibleRect; 570 scrollToVisiblePluginRect(); 571 } 572 573 void PluginWidgetAndroid::scrollToVisiblePluginRect() { 574 575 if (!m_hasFocus || m_requestedVisibleRect.isEmpty() || m_visibleDocRect.isEmpty()) { 576 #if DEBUG_VISIBLE_RECTS 577 PLUGIN_LOG("%s call m_hasFocus=%d m_requestedVisibleRect.isEmpty()=%d" 578 " m_visibleDocRect.isEmpty()=%d", __FUNCTION__, m_hasFocus, 579 m_requestedVisibleRect.isEmpty(), m_visibleDocRect.isEmpty()); 580 #endif 581 return; 582 } 583 // if the entire rect is already visible then we don't need to scroll 584 if (m_visibleDocRect.contains(m_requestedVisibleRect)) 585 return; 586 587 // find the center of the visibleRect in document coordinates 588 int rectCenterX = m_requestedVisibleRect.fLeft + m_requestedVisibleRect.width()/2; 589 int rectCenterY = m_requestedVisibleRect.fTop + m_requestedVisibleRect.height()/2; 590 591 // position the corner of the visible doc to center the requested rect 592 int scrollDocX = MAX(0, rectCenterX - (m_visibleDocRect.width()/2)); 593 int scrollDocY = MAX(0, rectCenterY - (m_visibleDocRect.height()/2)); 594 595 ScrollView* scrollView = m_pluginView->parent(); 596 android::WebViewCore* core = android::WebViewCore::getWebViewCore(scrollView); 597 #if DEBUG_VISIBLE_RECTS 598 PLUGIN_LOG("%s call scrollTo (%d,%d) to center (%d,%d)", __FUNCTION__, 599 scrollDocX, scrollDocX, rectCenterX, rectCenterY); 600 #endif 601 core->scrollTo(scrollDocX, scrollDocX, true); 602 } 603 604 void PluginWidgetAndroid::requestFullScreen() { 605 if (m_isFullScreen) { 606 return; 607 } 608 609 if (!m_embeddedView && m_drawingModel == kOpenGL_ANPDrawingModel) { 610 WebCore::PluginPackage* pkg = m_pluginView->plugin(); 611 NPP instance = m_pluginView->instance(); 612 613 jobject pluginSurface; 614 pkg->pluginFuncs()->getvalue(instance, kJavaSurface_ANPGetValue, 615 static_cast<void*>(&pluginSurface)); 616 617 // create the surface, but do not add it to the view hierarchy 618 jobject tempObj = m_core->createSurface(pluginSurface); 619 620 if (tempObj) { 621 JNIEnv* env = JSC::Bindings::getJNIEnv(); 622 m_embeddedView = env->NewGlobalRef(tempObj); 623 m_embeddedViewAttached = false; 624 } 625 } 626 627 if (!m_embeddedView) { 628 return; 629 } 630 631 // send event to notify plugin of full screen change 632 ANPEvent event; 633 SkANP::InitEvent(&event, kLifecycle_ANPEventType); 634 event.data.lifecycle.action = kEnterFullScreen_ANPLifecycleAction; 635 sendEvent(event); 636 637 // remove the embedded surface from the view hierarchy 638 if (m_drawingModel != kOpenGL_ANPDrawingModel) 639 m_core->destroySurface(m_embeddedView); 640 641 // add the full screen view 642 m_core->showFullScreenPlugin(m_embeddedView, m_fullScreenOrientation, 643 m_pluginView->instance()); 644 m_isFullScreen = true; 645 } 646 647 void PluginWidgetAndroid::exitFullScreen(bool pluginInitiated) { 648 if (!m_isFullScreen || !m_embeddedView) { 649 return; 650 } 651 652 // remove the full screen surface from the view hierarchy 653 if (pluginInitiated) { 654 m_core->hideFullScreenPlugin(); 655 } 656 657 // add the embedded view back 658 if (m_drawingModel != kOpenGL_ANPDrawingModel) 659 m_core->updateSurface(m_embeddedView, m_pluginWindow->x, m_pluginWindow->y, 660 m_pluginWindow->width, m_pluginWindow->height); 661 662 // send event to notify plugin of full screen change 663 ANPEvent event; 664 SkANP::InitEvent(&event, kLifecycle_ANPEventType); 665 event.data.lifecycle.action = kExitFullScreen_ANPLifecycleAction; 666 sendEvent(event); 667 668 m_isFullScreen = false; 669 } 670 671 void PluginWidgetAndroid::setFullScreenOrientation(ANPScreenOrientation orientation) { 672 673 int internalOrienationId; 674 /* We need to validate that the input is legitimate and then convert the 675 * value from the plugin enum to the enum used by the android view system. 676 * The view system values correspond to those values for the 677 * screenOrientation attribute in R.java (see also ActivityInfo.java). 678 */ 679 switch (orientation) { 680 case kFixedLandscape_ANPScreenOrientation: 681 internalOrienationId = 0; 682 break; 683 case kFixedPortrait_ANPScreenOrientation: 684 internalOrienationId = 1; 685 break; 686 case kLandscape_ANPScreenOrientation: 687 internalOrienationId = 6; 688 break; 689 case kPortrait_ANPScreenOrientation: 690 internalOrienationId = 7; 691 break; 692 default: 693 internalOrienationId = -1; 694 } 695 696 PLUGIN_LOG("%s orientation (%d)", __FUNCTION__, internalOrienationId); 697 m_fullScreenOrientation = internalOrienationId; 698 } 699 700 void PluginWidgetAndroid::requestCenterFitZoom() { 701 m_core->centerFitRect(m_pluginWindow->x, m_pluginWindow->y, 702 m_pluginWindow->width, m_pluginWindow->height); 703 } 704 705 void PluginWidgetAndroid::setPowerState(ANPPowerState powerState) { 706 if(m_powerState == powerState) 707 return; 708 709 // cleanup the old power state 710 switch (m_powerState) { 711 case kDefault_ANPPowerState: 712 break; 713 case kScreenOn_ANPPowerState: 714 m_core->keepScreenOn(false); 715 break; 716 } 717 718 // setup the new power state 719 switch (powerState) { 720 case kDefault_ANPPowerState: 721 break; 722 case kScreenOn_ANPPowerState: 723 m_core->keepScreenOn(true); 724 break; 725 } 726 727 m_powerState = powerState; 728 } 729 730