void PluginWidgetAndroid::scrollToVisiblePluginRect() {

    if (!m_hasFocus || m_requestedVisibleRect.isEmpty() || m_visibleDocRect.isEmpty()) {
#if DEBUG_VISIBLE_RECTS
        PLUGIN_LOG("%s call m_hasFocus=%d m_requestedVisibleRect.isEmpty()=%d"
                " m_visibleDocRect.isEmpty()=%d", __FUNCTION__, m_hasFocus,
                m_requestedVisibleRect.isEmpty(), m_visibleDocRect.isEmpty());
#endif
        return;
    }
    // if the entire rect is already visible then we don't need to scroll
    if (m_visibleDocRect.contains(m_requestedVisibleRect))
        return;

    // find the center of the visibleRect in document coordinates
    int rectCenterX = m_requestedVisibleRect.fLeft + m_requestedVisibleRect.width()/2;
    int rectCenterY = m_requestedVisibleRect.fTop + m_requestedVisibleRect.height()/2;

    // position the corner of the visible doc to center the requested rect
    int scrollDocX = MAX(0, rectCenterX - (m_visibleDocRect.width()/2));
    int scrollDocY = MAX(0, rectCenterY - (m_visibleDocRect.height()/2));

    ScrollView* scrollView = m_pluginView->parent();
    android::WebViewCore* core = android::WebViewCore::getWebViewCore(scrollView);
#if DEBUG_VISIBLE_RECTS
    PLUGIN_LOG("%s call scrollTo (%d,%d) to center (%d,%d)", __FUNCTION__,
            scrollDocX, scrollDocY, rectCenterX, rectCenterY);
#endif
    core->scrollTo(scrollDocX, scrollDocY, true);
}
void PluginWidgetAndroid::scrollToVisiblePluginRect() {

    if (!m_hasFocus || m_requestedVisibleRect.isEmpty() || m_visibleDocRect.isEmpty()) {
#if DEBUG_VISIBLE_RECTS
        PLUGIN_LOG("%s call m_hasFocus=%d m_requestedVisibleRect.isEmpty()=%d"
                " m_visibleDocRect.isEmpty()=%d", __FUNCTION__, m_hasFocus,
                m_requestedVisibleRect.isEmpty(), m_visibleDocRect.isEmpty());
#endif
        return;
    }
    // if the entire rect is already visible then we don't need to scroll
    if (m_visibleDocRect.contains(m_requestedVisibleRect))
        return;

    // find the center of the visibleRect in document coordinates
    int rectCenterX = m_requestedVisibleRect.fLeft + m_requestedVisibleRect.width()/2;
    int rectCenterY = m_requestedVisibleRect.fTop + m_requestedVisibleRect.height()/2;

    // find document coordinates for center of the visible screen
    int visibleDocCenterX = m_visibleDocRect.fLeft + m_visibleDocRect.width()/2;
    int visibleDocCenterY = m_visibleDocRect.fTop + m_visibleDocRect.height()/2;

    //compute the delta of the two points and scale to screen coordinates
    int deltaX = rectCenterX - visibleDocCenterX;
    int deltaY = rectCenterY - visibleDocCenterY;

    ScrollView* scrollView = m_pluginView->parent();
    android::WebViewCore* core = android::WebViewCore::getWebViewCore(scrollView);
#if DEBUG_VISIBLE_RECTS
    PLUGIN_LOG("%s call scrollBy (%d,%d)", __FUNCTION__, deltaX, deltaY);
#endif
    core->scrollBy(deltaX, deltaY, true);
}
void PluginWidgetAndroid::setVisibleRects(const ANPRectI rects[], int32_t count) {
#if DEBUG_VISIBLE_RECTS
    PLUGIN_LOG("%s count=%d", __FUNCTION__, count);
#endif
    // ensure the count does not exceed our allocated space
    if (count > MAX_REQUESTED_RECTS)
        count = MAX_REQUESTED_RECTS;

    // store the values in member variables
    m_requestedVisibleRectCount = count;
    memcpy(m_requestedVisibleRects, rects, count * sizeof(rects[0]));

#if DEBUG_VISIBLE_RECTS // FIXME: this fixes bad data from the plugin
    // take it out once plugin supplies better data
    for (int index = 0; index < count; index++) {
        PLUGIN_LOG("%s [%d](%d,%d,%d,%d)", __FUNCTION__, index,
            m_requestedVisibleRects[index].left,
            m_requestedVisibleRects[index].top,
            m_requestedVisibleRects[index].right,
            m_requestedVisibleRects[index].bottom);
        if (m_requestedVisibleRects[index].left ==
                m_requestedVisibleRects[index].right) {
            m_requestedVisibleRects[index].right += 1;
        }
        if (m_requestedVisibleRects[index].top ==
                m_requestedVisibleRects[index].bottom) {
            m_requestedVisibleRects[index].bottom += 1;
        }
    }
#endif
    computeVisiblePluginRect();
}
void PluginWidgetAndroid::setVisibleScreen(const ANPRectI& visibleDocRect, float zoom) {
#if DEBUG_VISIBLE_RECTS
    PLUGIN_LOG("%s (%d,%d,%d,%d)[%f]", __FUNCTION__, visibleDocRect.left,
            visibleDocRect.top, visibleDocRect.right,
            visibleDocRect.bottom, zoom);
#endif
    int oldScreenW = m_visibleDocRect.width();
    int oldScreenH = m_visibleDocRect.height();

    const bool zoomChanged = m_cachedZoomLevel != zoom;

    // make local copies of the parameters
    m_cachedZoomLevel = zoom;
    m_visibleDocRect.set(visibleDocRect.left,
                         visibleDocRect.top,
                         visibleDocRect.right,
                         visibleDocRect.bottom);

    int newScreenW = m_visibleDocRect.width();
    int newScreenH = m_visibleDocRect.height();

    // if the screen dimensions have changed by more than 5 pixels in either
    // direction then recompute the plugin's visible rectangle
    if (abs(oldScreenW - newScreenW) > 5 || abs(oldScreenH - newScreenH) > 5) {
        PLUGIN_LOG("%s VisibleDoc old=[%d,%d] new=[%d,%d] ", __FUNCTION__,
                   oldScreenW, oldScreenH, newScreenW, newScreenH);
        computeVisiblePluginRect();
    }

    sendSizeAndVisibilityEvents(zoomChanged);
}
void PluginWidgetAndroid::setVisibleScreen(const ANPRectI& visibleDocRect, float zoom) {
#if DEBUG_VISIBLE_RECTS
    PLUGIN_LOG("%s (%d,%d,%d,%d)[%f]", __FUNCTION__, visibleDocRect.left,
            visibleDocRect.top, visibleDocRect.right,
            visibleDocRect.bottom, zoom);
#endif
    // TODO update the bitmap size based on the zoom? (for kBitmap_ANPDrawingModel)

    int oldScreenW = m_visibleDocRect.width();
    int oldScreenH = m_visibleDocRect.height();

    // make local copies of the parameters
    m_zoomLevel = zoom;
    m_visibleDocRect.set(visibleDocRect.left,
                         visibleDocRect.top,
                         visibleDocRect.right,
                         visibleDocRect.bottom);

    int newScreenW = m_visibleDocRect.width();
    int newScreenH = m_visibleDocRect.height();

    // if the screen dimensions have changed by more than 5 pixels in either
    // direction then recompute the plugin's visible rectangle
    if (abs(oldScreenW - newScreenW) > 5 || abs(oldScreenH - newScreenH) > 5) {
        PLUGIN_LOG("%s VisibleDoc old=[%d,%d] new=[%d,%d] ", __FUNCTION__,
                   oldScreenW, oldScreenH, newScreenW, newScreenH);
        computeVisiblePluginRect();
    }

    bool visible = SkIRect::Intersects(m_visibleDocRect, m_pluginBounds);
    if(m_visible != visible) {

#if DEBUG_VISIBLE_RECTS
        PLUGIN_LOG("%p changeVisiblity[%d] pluginBounds(%d,%d,%d,%d)",
                   m_pluginView->instance(), visible,
                   m_pluginBounds.fLeft, m_pluginBounds.fTop,
                   m_pluginBounds.fRight, m_pluginBounds.fBottom);
#endif

        // change the visibility
        m_visible = visible;
        // send the event
        ANPEvent event;
        SkANP::InitEvent(&event, kLifecycle_ANPEventType);
        event.data.lifecycle.action = visible ? kOnScreen_ANPLifecycleAction
                                              : kOffScreen_ANPLifecycleAction;
        sendEvent(event);
    }
}
void PluginWidgetAndroid::setWindow(NPWindow* window, bool isTransparent) {

    // store the reference locally for easy lookup
    m_pluginWindow = window;

    // make a copy of the previous bounds
    SkIRect oldPluginBounds = m_pluginBounds;

    // keep a local copy of the plugin bounds because the m_pluginWindow pointer
    // gets updated values prior to this method being called
    m_pluginBounds.set(m_pluginWindow->x, m_pluginWindow->y,
                       m_pluginWindow->x + m_pluginWindow->width,
                       m_pluginWindow->y + m_pluginWindow->height);

    PLUGIN_LOG("%p PluginBounds (%d,%d,%d,%d)", m_pluginView->instance(),
               m_pluginBounds.fLeft, m_pluginBounds.fTop,
               m_pluginBounds.fRight, m_pluginBounds.fBottom);

    layoutSurface(m_pluginBounds != oldPluginBounds);

    if (m_drawingModel != kSurface_ANPDrawingModel) {
        m_flipPixelRef->safeUnref();
        m_flipPixelRef = new SkFlipPixelRef(computeConfig(isTransparent),
                                            window->width, window->height);
    }
}
PluginWidgetAndroid::~PluginWidgetAndroid() {
    PLUGIN_LOG("%p Deleting Plugin", m_pluginView->instance());
    m_acceptEvents = false;
    if (m_core && android::WebViewCore::isInstance(m_core)) {
        m_core->removePlugin(this);
        if (m_isFullScreen) {
            exitFullScreen(true);
        }
        //SAMSUNG CHANGES
        //Rakesh: Added a check to see whether surface to be 
        //destroyed is valid or not
        if (m_embeddedView && m_embeddedViewAttached) {
            m_core->destroySurface(m_embeddedView);
	    m_embeddedViewAttached = false;
        }
        //SAMSUNG CHANGES
    }

    // cleanup any remaining JNI References
    JNIEnv* env = JSC::Bindings::getJNIEnv();
    if (m_embeddedView) {
        env->DeleteGlobalRef(m_embeddedView);
    }

    m_flipPixelRef->safeUnref();
}
NS_IMETHODIMP nsPluginStreamListenerPeer::OnDataAvailable(
    nsIRequest* request, nsIInputStream* aIStream, uint64_t sourceOffset,
    uint32_t aLength) {
  if (mRequests.IndexOfObject(request) == -1) {
    MOZ_ASSERT(false, "Received OnDataAvailable for untracked request.");
    return NS_ERROR_UNEXPECTED;
  }

  if (mRequestFailed) return NS_ERROR_FAILURE;

  nsresult rv = NS_OK;

  if (!mPStreamListener) return NS_ERROR_FAILURE;

  const char* url = nullptr;
  GetURL(&url);

  PLUGIN_LOG(PLUGIN_LOG_NOISY,
             ("nsPluginStreamListenerPeer::OnDataAvailable this=%p request=%p, "
              "offset=%" PRIu64 ", length=%u, url=%s\n",
              this, request, sourceOffset, aLength, url ? url : "no url set"));

  nsCOMPtr<nsIInputStream> stream = aIStream;
  rv = mPStreamListener->OnDataAvailable(this, stream, aLength);

  // if a plugin returns an error, the peer must kill the stream
  //   else the stream and PluginStreamListener leak
  if (NS_FAILED(rv)) {
    request->Cancel(rv);
  }

  return rv;
}
void PluginWidgetAndroid::setFullScreenOrientation(ANPScreenOrientation orientation) {

    int internalOrienationId;
    /* We need to validate that the input is legitimate and then convert the
     * value from the plugin enum to the enum used by the android view system.
     * The view system values correspond to those values for the
     * screenOrientation attribute in R.java (see also ActivityInfo.java).
     */
    switch (orientation) {
        case kFixedLandscape_ANPScreenOrientation:
            internalOrienationId = 0;
            break;
        case kFixedPortrait_ANPScreenOrientation:
            internalOrienationId = 1;
            break;
        case kLandscape_ANPScreenOrientation:
            internalOrienationId = 6;
            break;
        case kPortrait_ANPScreenOrientation:
            internalOrienationId = 7;
            break;
        default:
            internalOrienationId = -1;
    }

    PLUGIN_LOG("%s orientation (%d)", __FUNCTION__, internalOrienationId);
    m_fullScreenOrientation = internalOrienationId;
}
NS_IMETHODIMP nsPluginStreamListenerPeer::OnStopRequest(nsIRequest* request,
                                                        nsresult aStatus) {
  nsresult rv = NS_OK;

  nsCOMPtr<nsIMultiPartChannel> mp = do_QueryInterface(request);
  if (!mp) {
    bool found = mRequests.RemoveObject(request);
    if (!found) {
      NS_ERROR("Received OnStopRequest for untracked request.");
    }
  }

  PLUGIN_LOG(
      PLUGIN_LOG_NOISY,
      ("nsPluginStreamListenerPeer::OnStopRequest this=%p aStatus=%" PRIu32
       " request=%p\n",
       this, static_cast<uint32_t>(aStatus), request));

  // if we still have pending stuff to do, lets not close the plugin socket.
  if (--mPendingRequests > 0) return NS_OK;

  if (!mPStreamListener) return NS_ERROR_FAILURE;

  nsCOMPtr<nsIChannel> channel = do_QueryInterface(request);
  if (!channel) return NS_ERROR_FAILURE;
  // Set the content type to ensure we don't pass null to the plugin
  nsAutoCString aContentType;
  rv = channel->GetContentType(aContentType);
  if (NS_FAILED(rv) && !mRequestFailed) return rv;

  if (!aContentType.IsEmpty()) mContentType = aContentType;

  // set error status if stream failed so we notify the plugin
  if (mRequestFailed) aStatus = NS_ERROR_FAILURE;

  if (NS_FAILED(aStatus)) {
    // on error status cleanup the stream
    // and return w/o OnFileAvailable()
    mPStreamListener->OnStopBinding(this, aStatus);
    return NS_OK;
  }

  if (mStartBinding) {
    // On start binding has been called
    mPStreamListener->OnStopBinding(this, aStatus);
  } else {
    // OnStartBinding hasn't been called, so complete the action.
    mPStreamListener->OnStartBinding(this);
    mPStreamListener->OnStopBinding(this, aStatus);
  }

  if (NS_SUCCEEDED(aStatus)) {
    mStreamComplete = true;
  }

  return NS_OK;
}
void PluginWidgetAndroid::sendSizeAndVisibilityEvents(const bool updateDimensions) {

    if (m_drawingModel == kOpenGL_ANPDrawingModel &&
            !m_layer->acquireNativeWindowForContent()) {
        m_drawEventDelayed = true;
        return;
    }

    // TODO update the bitmap size based on the zoom? (for kBitmap_ANPDrawingModel)
    const float zoomLevel = m_core->scale();

    // notify the plugin of the new size
    if (m_drawingModel == kOpenGL_ANPDrawingModel && updateDimensions && m_pluginWindow) {
        PLUGIN_LOG("%s (%d,%d)[%f]", __FUNCTION__, m_pluginWindow->width,
                m_pluginWindow->height, zoomLevel);
        ANPEvent event;
        SkANP::InitEvent(&event, kDraw_ANPEventType);
        event.data.draw.model = kOpenGL_ANPDrawingModel;
        event.data.draw.data.surface.width = m_pluginWindow->width * zoomLevel;
        event.data.draw.data.surface.height = m_pluginWindow->height * zoomLevel;
        sendEvent(event);
    }

    bool visible = SkIRect::Intersects(m_visibleDocRect, m_pluginBounds);
    if(m_visible != visible) {

#if DEBUG_VISIBLE_RECTS
        PLUGIN_LOG("%p changeVisiblity[%d] pluginBounds(%d,%d,%d,%d)",
                   m_pluginView->instance(), visible,
                   m_pluginBounds.fLeft, m_pluginBounds.fTop,
                   m_pluginBounds.fRight, m_pluginBounds.fBottom);
#endif

        // change the visibility
        m_visible = visible;
        // send the event
        ANPEvent event;
        SkANP::InitEvent(&event, kLifecycle_ANPEventType);
        event.data.lifecycle.action = visible ? kOnScreen_ANPLifecycleAction
                                              : kOffScreen_ANPLifecycleAction;
        sendEvent(event);
    }
}
void PluginWidgetAndroid::computeVisiblePluginRect() {

    // ensure the visibleDocRect has been set (i.e. not equal to zero)
    if (m_visibleDocRect.isEmpty() || !m_pluginWindow || m_requestedVisibleRectCount < 1)
        return;

    // create a rect that will contain as many of the rects that will fit on screen
    SkIRect visibleRect;
    visibleRect.setEmpty();

    for (int counter = 0; counter < m_requestedVisibleRectCount; counter++) {

        ANPRectI* rect = &m_requestedVisibleRects[counter];

        // create skia rect for easier manipulation and convert it to page coordinates
        SkIRect pluginRect;
        pluginRect.set(rect->left, rect->top, rect->right, rect->bottom);
        pluginRect.offset(m_pluginWindow->x, m_pluginWindow->y);

        // ensure the rect falls within the plugin's bounds
        if (!m_pluginBounds.contains(pluginRect)) {
#if DEBUG_VISIBLE_RECTS
            PLUGIN_LOG("%s (%d,%d,%d,%d) !contain (%d,%d,%d,%d)", __FUNCTION__,
                       m_pluginBounds.fLeft, m_pluginBounds.fTop,
                       m_pluginBounds.fRight, m_pluginBounds.fBottom,
                       pluginRect.fLeft, pluginRect.fTop,
                       pluginRect.fRight, pluginRect.fBottom);
            // assume that the desired outcome is to clamp to the container
            if (pluginRect.intersect(m_pluginBounds)) {
                visibleRect = pluginRect;
            }
#endif
            continue;
        }

        // combine this new rect with the higher priority rects
        pluginRect.join(visibleRect);

        // check to see if the new rect could be made to fit within the screen
        // bounds. If this is the highest priority rect then attempt to center
        // even if it doesn't fit on the screen.
        if (counter > 0 && (m_visibleDocRect.width() < pluginRect.width() ||
                            m_visibleDocRect.height() < pluginRect.height()))
          break;

        // set the new visible rect
        visibleRect = pluginRect;
    }

    m_requestedVisibleRect = visibleRect;
    scrollToVisiblePluginRect();
}
int auth_user_pass_verify_handler_func(void *handler_context)
{
    int r = 0;
    int http_code;
    deferred_handler_context_t *context = (deferred_handler_context_t*)handler_context;
    const char *auth_control_file = get_openvpn_env(
        "auth_control_file", (const char**)(context->envp));
    const char *username = get_openvpn_env("username", (const char**)(context->envp));
    
    /* I do not see any reasons why web server should know auth_control_file
     * to auth user. */
    static const char *exclude_list[] = {"auth_control_file", NULL};
    char *json_envp = openvpn_envp_to_json((const char **)context->envp, exclude_list);

    if (!username)
        username = "";

    PLUGIN_DEBUG("START - auth_user_pass_verify_handler_func.");
    PLUGIN_DEBUG("Data to post: %s. To URL: %s. auth_control_file: %s.",
                 json_envp, context->handler_url, auth_control_file);

    http_code = send_post(context->handler_url, json_envp);
    PLUGIN_DEBUG("HTTP Response code: %d.", http_code);

    if (http_code == 200) {
        PLUGIN_LOG("Auth for user %s SUCCESS.", username);
        write_auth_control_file(auth_control_file, 1);
    }
    else {
        PLUGIN_LOG("Auth for user %s FAILED.", username);
        write_auth_control_file(auth_control_file, 0);
    }

    free(json_envp);

    PLUGIN_DEBUG("END - auth_user_pass_verify_handler_func.");
    return r;
}
static bool getEntryPoint(PlatformModule module,
                          const char *name,
                          void **entry_point)
{
    dlerror();
    *entry_point = dlsym(module, name);
    const char *error = dlerror();
    if(error == NULL && *entry_point != NULL) {
        return true;
    } else {
        PLUGIN_LOG("Couldn't get entry point \"%s\": %s\n",
                   name, error);
        return false;
    }
}
void PluginWidgetAndroid::layoutSurface(bool pluginBoundsChanged) {

    if (m_drawingModel != kSurface_ANPDrawingModel)
        return;
    if (!m_pluginWindow)
        return;


    bool displayPlugin = m_pluginView->isVisible() && !m_isSurfaceClippedOut;
    PLUGIN_LOG("%p DisplayPlugin[%d] visible=[%d] clipped=[%d]",
            m_pluginView->instance(), displayPlugin,
            m_pluginView->isVisible(), m_isSurfaceClippedOut);

    // if the surface does not exist then create a new surface
    if (!m_embeddedView && displayPlugin) {

        WebCore::PluginPackage* pkg = m_pluginView->plugin();
        NPP instance = m_pluginView->instance();

        jobject pluginSurface;
        pkg->pluginFuncs()->getvalue(instance, kJavaSurface_ANPGetValue,
                                     static_cast<void*>(&pluginSurface));

        jobject tempObj = m_core->addSurface(pluginSurface,
                m_pluginWindow->x, m_pluginWindow->y,
                m_pluginWindow->width, m_pluginWindow->height);

        if (tempObj) {
            JNIEnv* env = JSC::Bindings::getJNIEnv();
            m_embeddedView = env->NewGlobalRef(tempObj);
            m_embeddedViewAttached = true;
        }
    // if the view is unattached but visible then attach it
    } else if (m_embeddedView && !m_embeddedViewAttached && displayPlugin && !m_isFullScreen) {
        m_core->updateSurface(m_embeddedView, m_pluginWindow->x, m_pluginWindow->y,
                              m_pluginWindow->width, m_pluginWindow->height);
        m_embeddedViewAttached = true;
    // if the view is attached but invisible then remove it
    } else if (m_embeddedView && m_embeddedViewAttached && !displayPlugin) {
        m_core->destroySurface(m_embeddedView);
        m_embeddedViewAttached = false;
    // if the plugin's bounds have changed and it's visible then update it
    } else if (pluginBoundsChanged && displayPlugin && !m_isFullScreen) {
        m_core->updateSurface(m_embeddedView, m_pluginWindow->x, m_pluginWindow->y,
                              m_pluginWindow->width, m_pluginWindow->height);

    }
}
示例#16
0
// Called by NewFullPagePluginStream()
nsresult nsPluginStreamListenerPeer::InitializeFullPage(nsIURI* aURL, nsNPAPIPluginInstance *aInstance)
{
  PLUGIN_LOG(PLUGIN_LOG_NORMAL,
             ("nsPluginStreamListenerPeer::InitializeFullPage instance=%p\n",aInstance));
  
  NS_ASSERTION(mPluginInstance == nsnull, "nsPluginStreamListenerPeer::InitializeFullPage mPluginInstance != nsnull");
  mPluginInstance = aInstance;
  
  mURL = aURL;
  
  mDataForwardToRequest = new nsHashtable(16, false);
  if (!mDataForwardToRequest)
    return NS_ERROR_FAILURE;

  mPendingRequests = 1;
  
  return NS_OK;
}
PluginWidgetAndroid::~PluginWidgetAndroid() {
    PLUGIN_LOG("%p Deleting Plugin", m_pluginView->instance());
    m_acceptEvents = false;
    if (m_core) {
        m_core->removePlugin(this);
        if (m_isFullScreen) {
            exitFullScreen(true);
        }
        if (m_embeddedView) {
            m_core->destroySurface(m_embeddedView);
        }
    }

    // cleanup any remaining JNI References
    JNIEnv* env = JSC::Bindings::getJNIEnv();
    if (m_embeddedView) {
        env->DeleteGlobalRef(m_embeddedView);
    }

    m_flipPixelRef->safeUnref();
}
void PluginWidgetAndroid::setWindow(NPWindow* window, bool isTransparent) {

    // store the reference locally for easy lookup
    m_pluginWindow = window;

    // make a copy of the previous bounds
    SkIRect oldPluginBounds = m_pluginBounds;

    // keep a local copy of the plugin bounds because the m_pluginWindow pointer
    // gets updated values prior to this method being called
    m_pluginBounds.set(m_pluginWindow->x, m_pluginWindow->y,
                       m_pluginWindow->x + m_pluginWindow->width,
                       m_pluginWindow->y + m_pluginWindow->height);

    PLUGIN_LOG("%p PluginBounds (%d,%d,%d,%d)", m_pluginView->instance(),
               m_pluginBounds.fLeft, m_pluginBounds.fTop,
               m_pluginBounds.fRight, m_pluginBounds.fBottom);

    const bool boundsChanged = m_pluginBounds != oldPluginBounds;

    //TODO hack to ensure that we grab the most recent screen dimensions and scale
    ANPRectI screenCoords;
    m_core->getVisibleScreen(screenCoords);
    float scale = m_core->scale();
    bool scaleChanged = m_cachedZoomLevel != scale;
    setVisibleScreen(screenCoords, scale);

    // if the scale changed then setVisibleScreen will call this function and
    // this call will potentially fire a duplicate draw event
    if (!scaleChanged) {
        sendSizeAndVisibilityEvents(boundsChanged);
    }
    layoutSurface(boundsChanged);

    if (m_drawingModel != kSurface_ANPDrawingModel) {
        SkSafeUnref(m_flipPixelRef);
        m_flipPixelRef = new SkFlipPixelRef(computeConfig(isTransparent),
                                            window->width, window->height);
    }
}
NS_IMETHODIMP nsPluginStreamListenerPeer::OnStopRequest(nsIRequest *request,
                                                        nsISupports* aContext,
                                                        nsresult aStatus)
{
  nsresult rv = NS_OK;

  nsCOMPtr<nsIMultiPartChannel> mp = do_QueryInterface(request);
  if (!mp) {
    bool found = mRequests.RemoveObject(request);
    if (!found) {
      NS_ERROR("Received OnStopRequest for untracked request.");
    }
  }

  PLUGIN_LOG(PLUGIN_LOG_NOISY,
             ("nsPluginStreamListenerPeer::OnStopRequest this=%p aStatus=%d request=%p\n",
              this, aStatus, request));

  // for ByteRangeRequest we're just updating the mDataForwardToRequest hash and return.
  nsCOMPtr<nsIByteRangeRequest> brr = do_QueryInterface(request);
  if (brr) {
    int64_t absoluteOffset64 = 0;
    brr->GetStartRange(&absoluteOffset64);
    // XXX support 64-bit offsets
    int32_t absoluteOffset = (int32_t)int64_t(absoluteOffset64);

    // remove the request from our data forwarding count hash.
    mDataForwardToRequest->Remove(absoluteOffset);


    PLUGIN_LOG(PLUGIN_LOG_NOISY,
               ("                          ::OnStopRequest for ByteRangeRequest Started=%d\n",
                absoluteOffset));
  } else {
    // if this is not byte range request and
    // if we are writting the stream to disk ourselves,
    // close & tear it down here
    mFileCacheOutputStream = nullptr;
  }

  // if we still have pending stuff to do, lets not close the plugin socket.
  if (--mPendingRequests > 0)
    return NS_OK;

  // we keep our connections around...
  nsCOMPtr<nsISupportsPRUint32> container = do_QueryInterface(aContext);
  if (container) {
    uint32_t magicNumber = 0;  // set it to something that is not the magic number.
    container->GetData(&magicNumber);
    if (magicNumber == MAGIC_REQUEST_CONTEXT) {
      // this is one of our range requests
      return NS_OK;
    }
  }

  if (!mPStreamListener)
    return NS_ERROR_FAILURE;

  nsCOMPtr<nsIChannel> channel = do_QueryInterface(request);
  if (!channel)
    return NS_ERROR_FAILURE;
  // Set the content type to ensure we don't pass null to the plugin
  nsAutoCString aContentType;
  rv = channel->GetContentType(aContentType);
  if (NS_FAILED(rv) && !mRequestFailed)
    return rv;

  if (!aContentType.IsEmpty())
    mContentType = aContentType;

  // set error status if stream failed so we notify the plugin
  if (mRequestFailed)
    aStatus = NS_ERROR_FAILURE;

  if (NS_FAILED(aStatus)) {
    // on error status cleanup the stream
    // and return w/o OnFileAvailable()
    mPStreamListener->OnStopBinding(this, aStatus);
    return NS_OK;
  }

  // call OnFileAvailable if plugin requests stream type StreamType_AsFile or StreamType_AsFileOnly
  if (mStreamType >= NP_ASFILE) {
    nsCOMPtr<nsIFile> localFile;
    if (mLocalCachedFileHolder)
      localFile = mLocalCachedFileHolder->file();
    else {
      // see if it is a file channel.
      nsCOMPtr<nsIFileChannel> fileChannel = do_QueryInterface(request);
      if (fileChannel) {
        fileChannel->GetFile(getter_AddRefs(localFile));
      }
    }

    if (localFile) {
      OnFileAvailable(localFile);
    }
  }

  if (mStartBinding) {
    // On start binding has been called
    mPStreamListener->OnStopBinding(this, aStatus);
  } else {
    // OnStartBinding hasn't been called, so complete the action.
    mPStreamListener->OnStartBinding(this);
    mPStreamListener->OnStopBinding(this, aStatus);
  }

  if (NS_SUCCEEDED(aStatus)) {
    mStreamComplete = true;
  }

  return NS_OK;
}
NS_IMETHODIMP nsPluginStreamListenerPeer::OnDataAvailable(nsIRequest *request,
                                                          nsISupports* aContext,
                                                          nsIInputStream *aIStream,
                                                          uint64_t sourceOffset,
                                                          uint32_t aLength)
{
  if (mRequests.IndexOfObject(GetBaseRequest(request)) == -1) {
    MOZ_ASSERT(false, "Received OnDataAvailable for untracked request.");
    return NS_ERROR_UNEXPECTED;
  }

  if (mRequestFailed)
    return NS_ERROR_FAILURE;

  if (mAbort) {
    uint32_t magicNumber = 0;  // set it to something that is not the magic number.
    nsCOMPtr<nsISupportsPRUint32> container = do_QueryInterface(aContext);
    if (container)
      container->GetData(&magicNumber);

    if (magicNumber != MAGIC_REQUEST_CONTEXT) {
      // this is not one of our range requests
      mAbort = false;
      return NS_BINDING_ABORTED;
    }
  }

  nsresult rv = NS_OK;

  if (!mPStreamListener)
    return NS_ERROR_FAILURE;

  const char * url = nullptr;
  GetURL(&url);

  PLUGIN_LOG(PLUGIN_LOG_NOISY,
             ("nsPluginStreamListenerPeer::OnDataAvailable this=%p request=%p, offset=%llu, length=%u, url=%s\n",
              this, request, sourceOffset, aLength, url ? url : "no url set"));

  // if the plugin has requested an AsFileOnly stream, then don't
  // call OnDataAvailable
  if (mStreamType != NP_ASFILEONLY) {
    // get the absolute offset of the request, if one exists.
    nsCOMPtr<nsIByteRangeRequest> brr = do_QueryInterface(request);
    if (brr) {
      if (!mDataForwardToRequest)
        return NS_ERROR_FAILURE;

      int64_t absoluteOffset64 = 0;
      brr->GetStartRange(&absoluteOffset64);

      // XXX handle 64-bit for real
      int32_t absoluteOffset = (int32_t)int64_t(absoluteOffset64);

      // we need to track how much data we have forwarded to the
      // plugin.

      // FIXME: http://bugzilla.mozilla.org/show_bug.cgi?id=240130
      //
      // Why couldn't this be tracked on the plugin info, and not in a
      // *hash table*?
      int32_t amtForwardToPlugin = mDataForwardToRequest->Get(absoluteOffset);
      mDataForwardToRequest->Put(absoluteOffset, (amtForwardToPlugin + aLength));

      SetStreamOffset(absoluteOffset + amtForwardToPlugin);
    }

    nsCOMPtr<nsIInputStream> stream = aIStream;

    // if we are caching the file ourselves to disk, we want to 'tee' off
    // the data as the plugin read from the stream.  We do this by the magic
    // of an input stream tee.

    if (mFileCacheOutputStream) {
      rv = NS_NewInputStreamTee(getter_AddRefs(stream), aIStream, mFileCacheOutputStream);
      if (NS_FAILED(rv))
        return rv;
    }

    rv =  mPStreamListener->OnDataAvailable(this,
                                            stream,
                                            aLength);

    // if a plugin returns an error, the peer must kill the stream
    //   else the stream and PluginStreamListener leak
    if (NS_FAILED(rv))
      request->Cancel(rv);
  }
  else
  {
    // if we don't read from the stream, OnStopRequest will never be called
    char* buffer = new char[aLength];
    uint32_t amountRead, amountWrote = 0;
    rv = aIStream->Read(buffer, aLength, &amountRead);

    // if we are caching this to disk ourselves, lets write the bytes out.
    if (mFileCacheOutputStream) {
      while (amountWrote < amountRead && NS_SUCCEEDED(rv)) {
        rv = mFileCacheOutputStream->Write(buffer, amountRead, &amountWrote);
      }
    }
    delete [] buffer;
  }
  return rv;
}
bool PluginPackage::fetchInfo()
{
    PLUGIN_LOG("Fetch Info Loading \"%s\"\n", m_path.utf8().data());

    // Open the library
    void *handle = dlopen(m_path.utf8().data(), RTLD_NOW);
    if(!handle) {
        PLUGIN_LOG("Couldn't load plugin library \"%s\": %s\n",
                   m_path.utf8().data(), dlerror());
        return false;
    }
    PLUGIN_LOG("Fetch Info Loaded %p\n", handle);
    
    // This object will call dlclose() and set m_module to NULL
    // when going out of scope.
    DynamicLibraryCloser dlCloser(&handle);
    
    // Get the three entry points we need for Linux Netscape Plug-ins
    NP_GetMIMEDescriptionFuncPtr NP_GetMIMEDescription;
    NPP_GetValueProcPtr NP_GetValue;
    if(!getEntryPoint(handle, "NP_GetMIMEDescription",
            (void **) &NP_GetMIMEDescription) ||
            !getEntryPoint(handle, "NP_GetValue", (void **) &NP_GetValue)) {
        // If any of those failed to resolve, fail the entire load
        return false;
    }
     
    // Get the plugin name and description using NP_GetValue
    const char *name;
    const char *description;
    if(NP_GetValue(NULL, NPPVpluginNameString, &name) != NPERR_NO_ERROR ||
            NP_GetValue(NULL, NPPVpluginDescriptionString, &description) !=
                NPERR_NO_ERROR) {
        PLUGIN_LOG("Couldn't get name/description using NP_GetValue\n");
        return false;
    }

    PLUGIN_LOG("Plugin name: \"%s\"\n", name);
    PLUGIN_LOG("Plugin description: \"%s\"\n", description);
    m_name = name;
    m_description = description;

    // fileName is just the trailing part of the path
    int last_slash = m_path.reverseFind('/');
    if(last_slash < 0)
        m_fileName = m_path;
    else
        m_fileName = m_path.substring(last_slash + 1);

    // Grab the MIME description. This is in the format, e.g:
    // application/x-somescriptformat:ssf:Some Script Format
    String mimeDescription(NP_GetMIMEDescription());
    PLUGIN_LOG("MIME description: \"%s\"\n", mimeDescription.utf8().data());
    // Clear out the current mappings.
    m_mimeToDescriptions.clear();
    m_mimeToExtensions.clear();    
    // Split the description into its component entries, separated by
    // semicolons.
    Vector<String> mimeEntries;
    mimeDescription.split(';', true, mimeEntries);
    // Iterate through the entries, adding them to the MIME mappings.
    for(Vector<String>::const_iterator it = mimeEntries.begin();
            it != mimeEntries.end(); ++it) {
        // Each part is split into 3 fields separated by colons
        // Field 1 is the MIME type (e.g "application/x-shockwave-flash").
        // Field 2 is a comma separated list of file extensions.
        // Field 3 is a human readable short description.
        const String &mimeEntry = *it;
        Vector<String> fields;
        mimeEntry.split(':', true, fields);
        if(fields.size() != 3) {
            PLUGIN_LOG("Bad MIME entry \"%s\"\n", mimeEntry.utf8().data());
            return false;
        }

        const String& mimeType = fields[0];
        Vector<String> extensions;
        fields[1].split(',', true, extensions);
        const String& description = fields[2];

        determineQuirks(mimeType);

        PLUGIN_LOG("mime_type: \"%s\"\n", mimeType.utf8().data());
        PLUGIN_LOG("extensions: \"%s\"\n", fields[1].utf8().data());
        PLUGIN_LOG("description: \"%s\"\n", description.utf8().data());
         
        // Map the mime type to the vector of extensions and the description
        if(!extensions.isEmpty())
            m_mimeToExtensions.set(mimeType, extensions);
        if(!description.isEmpty())
            m_mimeToDescriptions.set(mimeType, description);
    }

    PLUGIN_LOG("Fetch Info Loaded plugin details ok \"%s\"\n",
            m_path.utf8().data());

    // If this plugin needs to be kept in memory, unload the module now
    // and load it permanently.
    if (m_quirks.contains(PluginQuirkDontUnloadPlugin)) {
        dlCloser.ok();
        dlclose(handle);
        load();
    }
    
    // dlCloser will unload the plugin if required.
    return true;
}
bool PluginPackage::load()
{
    PLUGIN_LOG("tid:%d isActive:%d isLoaded:%d loadCount:%d\n",
               gettid(),
               m_freeLibraryTimer.isActive(),
               m_isLoaded,
               m_loadCount);
    if (m_freeLibraryTimer.isActive()) {
        ASSERT(m_module);
        m_freeLibraryTimer.stop();
    } else if (m_isLoaded) {
        if (m_quirks.contains(PluginQuirkDontAllowMultipleInstances))
            return false;
        m_loadCount++;
        PLUGIN_LOG("Already loaded, count now %d\n", m_loadCount);
        return true;
    }
    ASSERT(m_loadCount == 0);
    ASSERT(m_module == NULL);

    PLUGIN_LOG("Loading \"%s\"\n", m_path.utf8().data());

    // Open the library
    void *handle = dlopen(m_path.utf8().data(), RTLD_NOW);
    if(!handle) {
        PLUGIN_LOG("Couldn't load plugin library \"%s\": %s\n",
                   m_path.utf8().data(), dlerror());
        return false;
    }
    m_module = handle;
    PLUGIN_LOG("Fetch Info Loaded %p\n", m_module);
    // This object will call dlclose() and set m_module to NULL
    // when going out of scope.
    DynamicLibraryCloser dlCloser(&m_module);
    
    
    NP_InitializeFuncPtr NP_Initialize;
    if(!getEntryPoint(m_module, "NP_Initialize", (void **) &NP_Initialize) || 
            !getEntryPoint(handle, "NP_Shutdown", (void **) &m_NPP_Shutdown)) {
        PLUGIN_LOG("Couldn't find Initialize function\n");
        return false;
    }

    // Provide the plugin with our browser function table and grab its
    // plugin table. Provide the Java environment and the Plugin which
    // can be used to override the defaults if the plugin wants.
    initializeBrowserFuncs();
    // call this afterwards, which may re-initialize some methods, but ensures
    // that any additional (or changed) procs are set. There is no real attempt
    // to have this step be minimal (i.e. only what we add/override), since the
    // core version (initializeBrowserFuncs) can change in the future.
    initializeExtraBrowserFuncs(&m_browserFuncs);

    memset(&m_pluginFuncs, 0, sizeof(m_pluginFuncs));
    m_pluginFuncs.size = sizeof(m_pluginFuncs);
    if(NP_Initialize(&m_browserFuncs,
                     &m_pluginFuncs,
                     JSC::Bindings::getJNIEnv()) != NPERR_NO_ERROR) {
        PLUGIN_LOG("Couldn't initialize plugin\n");
        return false;
    }

    // Don't close the library - loaded OK.
    dlCloser.ok();
    // Retain the handle so we can close it in the future.
    m_module = handle;
    m_isLoaded = true;
    ++m_loadCount;
    PLUGIN_LOG("Initial load ok, count now %d\n", m_loadCount);
    return true;
}
void anp_logPluginEvent(void* npp, const ANPEvent* evt, int16 returnVal, int elapsedTime) {

    switch(evt->eventType) {

        case kNull_ANPEventType:
            PLUGIN_LOG("%p EVENT::NULL", npp);
            break;

        case kKey_ANPEventType:
            if(evt->data.key.action < ARRAY_COUNT(inputActions)) {
                anp_logPlugin("%p EVENT::KEY[%d] time=%d action=%s code=%d vcode=%d unichar=%d repeat=%d mods=%x",
                        npp, returnVal, elapsedTime, inputActions[evt->data.key.action],
                        evt->data.key.nativeCode, evt->data.key.virtualCode,
                        evt->data.key.unichar, evt->data.key.repeatCount,
                        evt->data.key.modifiers);
            } else {
                PLUGIN_LOG("%p EVENT::KEY[%d] unknown action", npp, returnVal);
            }
            break;

        case kMouse_ANPEventType:
            if(evt->data.mouse.action < ARRAY_COUNT(inputActions)) {
                anp_logPlugin("%p EVENT::MOUSE[%d] time=%d action=%s [%d %d]", npp,
                        returnVal, elapsedTime, inputActions[evt->data.mouse.action],
                        evt->data.touch.x, evt->data.touch.y);
            } else {
                anp_logPlugin("%p EVENT::MOUSE[%d] unknown action", npp, returnVal);
            }
            break;

        case kTouch_ANPEventType:
            if(evt->data.touch.action < ARRAY_COUNT(inputActions)) {

                anp_logPlugin("%p EVENT::TOUCH[%d] time=%d action=%s [%d %d]",
                        npp, returnVal, elapsedTime,
                        inputActions[evt->data.touch.action], evt->data.touch.x,
                        evt->data.touch.y);
            } else {
                anp_logPlugin("%p EVENT::TOUCH[%d] unknown action", npp, returnVal);
            }
            break;

        case kDraw_ANPEventType:
            if (evt->data.draw.model == kBitmap_ANPDrawingModel) {
                anp_logPlugin("%p EVENT::DRAW bitmap time=%d format=%d clip=[%d,%d,%d,%d]",
                        npp, elapsedTime, evt->data.draw.data.bitmap.format,
                        evt->data.draw.clip.left, evt->data.draw.clip.top,
                        evt->data.draw.clip.right, evt->data.draw.clip.bottom);
            } else {
                anp_logPlugin("%p EVENT::DRAW unknown drawing model", npp);
            }
            break;

        case kLifecycle_ANPEventType:
            if(evt->data.lifecycle.action < ARRAY_COUNT(lifecycleActions)) {
                anp_logPlugin("%p EVENT::LIFECYCLE time=%d action=%s", npp, elapsedTime,
                        lifecycleActions[evt->data.lifecycle.action]);
            } else {
                anp_logPlugin("%p EVENT::LIFECYCLE unknown action", npp);
            }
            break;

        case kCustom_ANPEventType:
            anp_logPlugin("%p EVENT::CUSTOM time=%d", npp, elapsedTime);
            break;

        default:
            anp_logPlugin("%p EVENT::UNKNOWN", npp);
            break;
    }
}
void PluginWidgetAndroid::init(android::WebViewCore* core) {
    m_core = core;
    m_core->addPlugin(this);
    m_acceptEvents = true;
    PLUGIN_LOG("%p Initialized Plugin", m_pluginView->instance());
}