/*static*/ already_AddRefed<gfxASurface>
ShadowLayerForwarder::PlatformOpenDescriptor(OpenMode aMode,
                                             const SurfaceDescriptor& aSurface)
{
  SAMPLE_LABEL("ShadowLayerForwarder", "PlatformOpenDescriptor");
  if (SurfaceDescriptor::TSurfaceDescriptorGralloc != aSurface.type()) {
    return nullptr;
  }

  sp<GraphicBuffer> buffer =
    GrallocBufferActor::GetFrom(aSurface.get_SurfaceDescriptorGralloc());
  uint32_t usage = GRALLOC_USAGE_SW_READ_OFTEN;
  if (OPEN_READ_WRITE == aMode) {
    usage |= GRALLOC_USAGE_SW_WRITE_OFTEN;
  }
  void *vaddr;
  DebugOnly<status_t> status = buffer->lock(usage, &vaddr);
  // If we fail to lock, we'll just end up aborting anyway.
  MOZ_ASSERT(status == OK);

  gfxIntSize size = gfxIntSize(buffer->getWidth(), buffer->getHeight());
  gfxImageFormat format = ImageFormatForPixelFormat(buffer->getPixelFormat());
  long pixelStride = buffer->getStride();
  long byteStride = pixelStride * gfxASurface::BytePerPixelFromFormat(format);

  nsRefPtr<gfxASurface> surf =
    new gfxImageSurface((unsigned char*)vaddr, size, byteStride, format);
  return surf->CairoStatus() ? nullptr : surf.forget();
}
PRUint32
nsInputStreamPump::OnStateStop()
{
    SAMPLE_LABEL("Input", "nsInputStreamPump::OnStateTransfer");
    LOG(("  OnStateStop [this=%x status=%x]\n", this, mStatus));

    // if an error occurred, we must be sure to pass the error onto the async
    // stream.  in some cases, this is redundant, but since close is idempotent,
    // this is OK.  otherwise, be sure to honor the "close-when-done" option.

    if (NS_FAILED(mStatus))
        mAsyncStream->CloseWithStatus(mStatus);
    else if (mCloseWhenDone)
        mAsyncStream->Close();

    mAsyncStream = 0;
    mTargetThread = 0;
    mIsPending = false;

    mListener->OnStopRequest(this, mListenerContext, mStatus);
    mListener = 0;
    mListenerContext = 0;

    if (mLoadGroup)
        mLoadGroup->RemoveRequest(this, nullptr, mStatus);

    return STATE_IDLE;
}
bool
ShadowLayerForwarder::PlatformAllocBuffer(const gfxIntSize& aSize,
                                          gfxASurface::gfxContentType aContent,
                                          uint32_t aCaps,
                                          SurfaceDescriptor* aBuffer)
{
  // Some GL implementations fail to render gralloc textures with
  // width < 64.  There's not much point in gralloc'ing buffers that
  // small anyway, so fall back on shared memory plus a texture
  // upload.
  if (aSize.width < 64) {
    return false;
  }
  SAMPLE_LABEL("ShadowLayerForwarder", "PlatformAllocBuffer");
  // Gralloc buffers are efficiently mappable as gfxImageSurface, so
  // no need to check |aCaps & MAP_AS_IMAGE_SURFACE|.
  MaybeMagicGrallocBufferHandle handle;
  PGrallocBufferChild* gc =
    mShadowManager->SendPGrallocBufferConstructor(aSize, aContent, &handle);
  if (!gc) {
    NS_ERROR("GrallocBufferConstructor failed by returned null");
    return false;
  } else if (handle.Tnull_t == handle.type()) {
    NS_ERROR("GrallocBufferConstructor failed by returning handle with type Tnull_t");
    PGrallocBufferChild::Send__delete__(gc);
    return false;
  }

  GrallocBufferActor* gba = static_cast<GrallocBufferActor*>(gc);
  gba->InitFromHandle(handle.get_MagicGrallocBufferHandle());

  *aBuffer = SurfaceDescriptorGralloc(nullptr, gc, aSize, /* external */ false);
  return true;
}
Exemple #4
0
SharedSurface*
SurfaceStream_TripleBuffer::SwapProducer(SurfaceFactory* factory,
        const gfxIntSize& size)
{
    SAMPLE_LABEL("SurfaceStream_TripleBuffer", "SwapProducer");

    MonitorAutoLock lock(mMonitor);
    if (mProducer) {
        RecycleScraps(factory);

        // If WaitForCompositor succeeds, mStaging has moved to mConsumer.
        // If it failed, we might have to scrap it.
        if (mStaging && !WaitForCompositor())
            Scrap(mStaging);

        MOZ_ASSERT(!mStaging);
        Move(mProducer, mStaging);
        mStaging->Fence();
    }

    MOZ_ASSERT(!mProducer);
    New(factory, size, mProducer);

    return mProducer;
}
NS_IMETHODIMP
PluginStreamListener::OnStartRequest(nsIRequest* request, nsISupports *ctxt)
{
  SAMPLE_LABEL("PluginStreamListener", "OnStartRequest");

  nsCOMPtr<nsIContent> embed = mPluginDoc->GetPluginContent();
  nsCOMPtr<nsIObjectLoadingContent> objlc = do_QueryInterface(embed);
  nsCOMPtr<nsIStreamListener> objListener = do_QueryInterface(objlc);

  if (!objListener) {
    NS_NOTREACHED("PluginStreamListener without appropriate content node");
    return NS_BINDING_ABORTED;
  }

  SetStreamListener(objListener);

  // Sets up the ObjectLoadingContent tag as if it is waiting for a
  // channel, so it can proceed with a load normally once it gets OnStartRequest
  nsresult rv = objlc->InitializeFromChannel(request);
  if (NS_FAILED(rv)) {
    NS_NOTREACHED("InitializeFromChannel failed");
    return rv;
  }

  // Note that because we're now hooked up to a plugin listener, this will
  // likely spawn a plugin, which may re-enter.
  return MediaDocumentStreamListener::OnStartRequest(request, ctxt);
}
/*static*/ PGrallocBufferParent*
GrallocBufferActor::Create(const gfxIntSize& aSize,
                           const gfxContentType& aContent,
                           MaybeMagicGrallocBufferHandle* aOutHandle)
{
  SAMPLE_LABEL("GrallocBufferActor", "Create");
  GrallocBufferActor* actor = new GrallocBufferActor();
  *aOutHandle = null_t();
  android::PixelFormat format = PixelFormatForContentType(aContent);
  sp<GraphicBuffer> buffer(
    new GraphicBuffer(aSize.width, aSize.height, format,
                      GraphicBuffer::USAGE_SW_READ_OFTEN |
                      GraphicBuffer::USAGE_SW_WRITE_OFTEN |
                      GraphicBuffer::USAGE_HW_TEXTURE));
  if (buffer->initCheck() != OK)
    return actor;

  size_t bpp = gfxASurface::BytePerPixelFromFormat(
      gfxPlatform::GetPlatform()->OptimalFormatForContent(aContent));
  actor->mAllocBytes = aSize.width * aSize.height * bpp;
  sCurrentAlloc += actor->mAllocBytes;

  actor->mGraphicBuffer = buffer;
  *aOutHandle = MagicGrallocBufferHandle(buffer);
  return actor;
}
PRUint32
nsInputStreamPump::OnStateStart()
{
    SAMPLE_LABEL("nsInputStreamPump", "OnStateStart");
    LOG(("  OnStateStart [this=%x]\n", this));

    nsresult rv;

    // need to check the reason why the stream is ready.  this is required
    // so our listener can check our status from OnStartRequest.
    // XXX async streams should have a GetStatus method!
    if (NS_SUCCEEDED(mStatus)) {
        PRUint32 avail;
        rv = mAsyncStream->Available(&avail);
        if (NS_FAILED(rv) && rv != NS_BASE_STREAM_CLOSED)
            mStatus = rv;
    }

    rv = mListener->OnStartRequest(this, mListenerContext);

    // an error returned from OnStartRequest should cause us to abort; however,
    // we must not stomp on mStatus if already canceled.
    if (NS_FAILED(rv) && NS_SUCCEEDED(mStatus))
        mStatus = rv;

    return NS_SUCCEEDED(mStatus) ? STATE_TRANSFER : STATE_STOP;
}
nsresult nsViewManager::DispatchEvent(nsGUIEvent *aEvent, nsIView* aView, nsEventStatus* aStatus)
{
  SAMPLE_LABEL("event", "nsViewManager::DispatchEvent");

  if ((NS_IS_MOUSE_EVENT(aEvent) &&
       // Ignore mouse events that we synthesize.
       static_cast<nsMouseEvent*>(aEvent)->reason == nsMouseEvent::eReal &&
       // Ignore mouse exit and enter (we'll get moves if the user
       // is really moving the mouse) since we get them when we
       // create and destroy widgets.
       aEvent->message != NS_MOUSE_EXIT &&
       aEvent->message != NS_MOUSE_ENTER) ||
      NS_IS_KEY_EVENT(aEvent) ||
      NS_IS_IME_EVENT(aEvent) ||
      aEvent->message == NS_PLUGIN_INPUT_EVENT) {
    gLastUserEventTime = PR_IntervalToMicroseconds(PR_IntervalNow());
  }

  // Find the view whose coordinates system we're in.
  nsIView* view = aView;
  bool dispatchUsingCoordinates = NS_IsEventUsingCoordinates(aEvent);
  if (dispatchUsingCoordinates) {
    // Will dispatch using coordinates. Pretty bogus but it's consistent
    // with what presshell does.
    view = GetDisplayRootFor(view);
  }

  // If the view has no frame, look for a view that does.
  nsIFrame* frame = view->GetFrame();
  if (!frame &&
      (dispatchUsingCoordinates || NS_IS_KEY_EVENT(aEvent) ||
       NS_IS_IME_RELATED_EVENT(aEvent) ||
       NS_IS_NON_RETARGETED_PLUGIN_EVENT(aEvent) ||
       aEvent->message == NS_PLUGIN_ACTIVATE ||
       aEvent->message == NS_PLUGIN_FOCUS ||
       aEvent->message == NS_PLUGIN_RESOLUTION_CHANGED)) {
    while (view && !view->GetFrame()) {
      view = view->GetParent();
    }

    if (view) {
      frame = view->GetFrame();
    }
  }

  if (nullptr != frame) {
    // Hold a refcount to the presshell. The continued existence of the
    // presshell will delay deletion of this view hierarchy should the event
    // want to cause its destruction in, say, some JavaScript event handler.
    nsCOMPtr<nsIPresShell> shell = view->GetViewManager()->GetPresShell();
    if (shell) {
      return shell->HandleEvent(frame, aEvent, false, aStatus);
    }
  }

  *aStatus = nsEventStatus_eIgnore;

  return NS_OK;
}
Exemple #9
0
bool
SurfaceStream_TripleBuffer_Async::WaitForCompositor()
{
    SAMPLE_LABEL("SurfaceStream_TripleBuffer_Async", "WaitForCompositor");

    // We are assumed to be locked
    while (mStaging)
        mMonitor.Wait();

    return true;
}
/*static*/ already_AddRefed<TextureImage>
ShadowLayerManager::OpenDescriptorForDirectTexturing(GLContext* aGL,
                                                     const SurfaceDescriptor& aDescriptor,
                                                     GLenum aWrapMode)
{
  SAMPLE_LABEL("ShadowLayerManager", "OpenDescriptorForDirectTexturing");
  if (SurfaceDescriptor::TSurfaceDescriptorGralloc != aDescriptor.type()) {
    return nullptr;
  }
  sp<GraphicBuffer> buffer = GrallocBufferActor::GetFrom(aDescriptor);
  return aGL->CreateDirectTextureImage(buffer.get(), aWrapMode);
}
void
ThebesLayerBuffer::DrawBufferWithRotation(gfxContext* aTarget, float aOpacity,
                                          gfxASurface* aMask,
                                          const gfxMatrix* aMaskTransform)
{
  SAMPLE_LABEL("ThebesLayerBuffer", "DrawBufferWithRotation");
  // Draw four quadrants. We could use REPEAT_, but it's probably better
  // not to, to be performance-safe.
  DrawBufferQuadrant(aTarget, LEFT, TOP, aOpacity, aMask, aMaskTransform);
  DrawBufferQuadrant(aTarget, RIGHT, TOP, aOpacity, aMask, aMaskTransform);
  DrawBufferQuadrant(aTarget, LEFT, BOTTOM, aOpacity, aMask, aMaskTransform);
  DrawBufferQuadrant(aTarget, RIGHT, BOTTOM, aOpacity, aMask, aMaskTransform);
}
NS_IMETHODIMP
PluginStreamListener::OnStartRequest(nsIRequest* request, nsISupports *ctxt)
{
  SAMPLE_LABEL("PluginStreamListener", "OnStartRequest");
  // Have to set up our plugin stuff before we call OnStartRequest, so
  // that the plugin listener can get that call.
  nsresult rv = SetupPlugin();

  NS_ASSERTION(NS_FAILED(rv) || mNextStream,
               "We should have a listener by now");
  nsresult rv2 = MediaDocumentStreamListener::OnStartRequest(request, ctxt);
  return NS_SUCCEEDED(rv) ? rv2 : rv;
}
/*static*/ bool
ShadowLayerForwarder::PlatformCloseDescriptor(const SurfaceDescriptor& aDescriptor)
{
  SAMPLE_LABEL("ShadowLayerForwarder", "PlatformCloseDescriptor");
  if (SurfaceDescriptor::TSurfaceDescriptorGralloc != aDescriptor.type()) {
    return false;
  }

  sp<GraphicBuffer> buffer = GrallocBufferActor::GetFrom(aDescriptor);
  // If the buffer wasn't lock()d, this probably blows up.  But since
  // PlatformCloseDescriptor() is private and only used by
  // AutoOpenSurface, we want to know if the logic is wrong there.
  buffer->unlock();
  return true;
}
NS_IMETHODIMP
nsInputStreamPump::OnInputStreamReady(nsIAsyncInputStream *stream)
{
    LOG(("nsInputStreamPump::OnInputStreamReady [this=%x]\n", this));

    SAMPLE_LABEL("Input", "nsInputStreamPump::OnInputStreamReady");
    // this function has been called from a PLEvent, so we can safely call
    // any listener or progress sink methods directly from here.

    for (;;) {
        if (mSuspendCount || mState == STATE_IDLE) {
            mWaiting = false;
            break;
        }

        PRUint32 nextState;
        switch (mState) {
        case STATE_START:
            nextState = OnStateStart();
            break;
        case STATE_TRANSFER:
            nextState = OnStateTransfer();
            break;
        case STATE_STOP:
            nextState = OnStateStop();
            break;
        default:
            nextState = 0;
            NS_NOTREACHED("Unknown enum value.");
            return NS_ERROR_UNEXPECTED;
        }

        if (mState == nextState && !mSuspendCount) {
            NS_ASSERTION(mState == STATE_TRANSFER, "unexpected state");
            NS_ASSERTION(NS_SUCCEEDED(mStatus), "unexpected status");

            mWaiting = false;
            mStatus = EnsureWaiting();
            if (NS_SUCCEEDED(mStatus))
                break;
            
            nextState = STATE_STOP;
        }

        mState = nextState;
    }
    return NS_OK;
}
Exemple #15
0
// Unlike other cross-process forwarding methods, GetValue needs to replicate
// the following behaviour of DOMStorageImpl::GetValue:
//
// - if a security error occurs, or the item isn't found, return null without
//   propogating the error.
//
// If DOMStorageImpl::GetValue ever changes its behaviour, this should be kept
// in sync.
nsIDOMStorageItem*
StorageChild::GetValue(bool aCallerSecure, const nsAString& aKey, nsresult* rv)
{
  SAMPLE_LABEL("StorageChild", "GetValue");
  nsresult rv2 = *rv = NS_OK;
  StorageItem storageItem;
  SendGetValue(aCallerSecure, mSessionOnly, nsString(aKey), &storageItem, &rv2);
  if (rv2 == NS_ERROR_DOM_SECURITY_ERR || rv2 == NS_ERROR_DOM_NOT_FOUND_ERR)
    return nullptr;
  *rv = rv2;
  if (NS_FAILED(*rv) || storageItem.type() == StorageItem::Tnull_t)
    return nullptr;
  const ItemData& data = storageItem.get_ItemData();
  nsIDOMStorageItem* item = new nsDOMStorageItem(this, aKey, data.value(),
                                                 data.secure());
  return item;
}
/*static*/ PGrallocBufferParent*
GrallocBufferActor::Create(const gfxIntSize& aSize,
                           const gfxContentType& aContent,
                           MaybeMagicGrallocBufferHandle* aOutHandle)
{
  SAMPLE_LABEL("GrallocBufferActor", "Create");
  GrallocBufferActor* actor = new GrallocBufferActor();
  *aOutHandle = null_t();
  android::PixelFormat format = PixelFormatForContentType(aContent);
  sp<GraphicBuffer> buffer(
    new GraphicBuffer(aSize.width, aSize.height, format,
                      GraphicBuffer::USAGE_SW_READ_OFTEN |
                      GraphicBuffer::USAGE_SW_WRITE_OFTEN |
                      GraphicBuffer::USAGE_HW_TEXTURE));
  if (buffer->initCheck() != OK)
    return actor;

  actor->mGraphicBuffer = buffer;
  *aOutHandle = MagicGrallocBufferHandle(buffer);
  return actor;
}
bool
ShadowLayerForwarder::PlatformAllocBuffer(const gfxIntSize& aSize,
                                          gfxASurface::gfxContentType aContent,
                                          uint32_t aCaps,
                                          SurfaceDescriptor* aBuffer)
{
  SAMPLE_LABEL("ShadowLayerForwarder", "PlatformAllocBuffer");
  // Gralloc buffers are efficiently mappable as gfxImageSurface, so
  // no need to check |aCaps & MAP_AS_IMAGE_SURFACE|.
  MaybeMagicGrallocBufferHandle handle;
  PGrallocBufferChild* gc =
    mShadowManager->SendPGrallocBufferConstructor(aSize, aContent, &handle);
  if (handle.Tnull_t == handle.type()) {
    PGrallocBufferChild::Send__delete__(gc);
    return false;
  }

  GrallocBufferActor* gba = static_cast<GrallocBufferActor*>(gc);
  gba->InitFromHandle(handle.get_MagicGrallocBufferHandle());

  *aBuffer = SurfaceDescriptorGralloc(nullptr, gc, /* external */ false);
  return true;
}
NS_IMETHODIMP 
nsStreamLoader::OnStopRequest(nsIRequest* request, nsISupports *ctxt,
                              nsresult aStatus)
{
  SAMPLE_LABEL("network", "nsStreamLoader::OnStopRequest");
  if (mObserver) {
    // provide nsIStreamLoader::request during call to OnStreamComplete
    mRequest = request;
    nsresult rv = mObserver->OnStreamComplete(this, mContext, aStatus,
                                              mLength, mData);
    if (rv == NS_SUCCESS_ADOPTED_DATA) {
      // the observer now owns the data buffer, and the loader must
      // not deallocate it
      mData = nullptr;
      mLength = 0;
      mAllocated = 0;
    }
    // done.. cleanup
    mRequest = 0;
    mObserver = 0;
    mContext = 0;
  }
  return NS_OK;
}
void
RestyleTracker::DoProcessRestyles()
{
  SAMPLE_LABEL("CSS", "ProcessRestyles");
  // Make sure to not rebuild quote or counter lists while we're
  // processing restyles
  mFrameConstructor->BeginUpdate();

  mFrameConstructor->mInStyleRefresh = true;

  // loop so that we process any restyle events generated by processing
  while (mPendingRestyles.Count()) {
    if (mHaveLaterSiblingRestyles) {
      // Convert them to individual restyles on all the later siblings
      nsAutoTArray<nsRefPtr<Element>, RESTYLE_ARRAY_STACKSIZE> laterSiblingArr;
      LaterSiblingCollector siblingCollector = { this, &laterSiblingArr };
      mPendingRestyles.Enumerate(CollectLaterSiblings, &siblingCollector);
      for (PRUint32 i = 0; i < laterSiblingArr.Length(); ++i) {
        Element* element = laterSiblingArr[i];
        for (nsIContent* sibling = element->GetNextSibling();
             sibling;
             sibling = sibling->GetNextSibling()) {
          if (sibling->IsElement() &&
              AddPendingRestyle(sibling->AsElement(), eRestyle_Subtree,
                                NS_STYLE_HINT_NONE)) {
              // Nothing else to do here; we'll handle the following
              // siblings when we get to |sibling| in laterSiblingArr.
            break;
          }
        }
      }

      // Now remove all those eRestyle_LaterSiblings bits
      for (PRUint32 i = 0; i < laterSiblingArr.Length(); ++i) {
        Element* element = laterSiblingArr[i];
        NS_ASSERTION(element->HasFlag(RestyleBit()), "How did that happen?");
        RestyleData data;
#ifdef DEBUG
        bool found =
#endif
          mPendingRestyles.Get(element, &data);
        NS_ASSERTION(found, "Where did our entry go?");
        data.mRestyleHint =
          nsRestyleHint(data.mRestyleHint & ~eRestyle_LaterSiblings);

        mPendingRestyles.Put(element, data);
      }

      mHaveLaterSiblingRestyles = false;
    }

    PRUint32 rootCount;
    while ((rootCount = mRestyleRoots.Length())) {
      // Make sure to pop the element off our restyle root array, so
      // that we can freely append to the array as we process this
      // element.
      nsRefPtr<Element> element;
      element.swap(mRestyleRoots[rootCount - 1]);
      mRestyleRoots.RemoveElementAt(rootCount - 1);

      // Do the document check before calling GetRestyleData, since we
      // don't want to do the sibling-processing GetRestyleData does if
      // the node is no longer relevant.
      if (element->GetCurrentDoc() != Document()) {
        // Content node has been removed from our document; nothing else
        // to do here
        continue;
      }

      RestyleData data;
      if (!GetRestyleData(element, &data)) {
        continue;
      }

      ProcessOneRestyle(element, data.mRestyleHint, data.mChangeHint);
    }

    if (mHaveLaterSiblingRestyles) {
      // Keep processing restyles for now
      continue;
    }

    // Now we only have entries with change hints left.  To be safe in
    // case of reentry from the handing of the change hint, use a
    // scratch array instead of calling out to ProcessOneRestyle while
    // enumerating the hashtable.  Use the stack if we can, otherwise
    // fall back on heap-allocation.
    nsAutoTArray<RestyleEnumerateData, RESTYLE_ARRAY_STACKSIZE> restyleArr;
    RestyleEnumerateData* restylesToProcess =
      restyleArr.AppendElements(mPendingRestyles.Count());
    if (restylesToProcess) {
      RestyleEnumerateData* lastRestyle = restylesToProcess;
      RestyleCollector collector = { this, &lastRestyle };
      mPendingRestyles.Enumerate(CollectRestyles, &collector);

      // Clear the hashtable now that we don't need it anymore
      mPendingRestyles.Clear();

      for (RestyleEnumerateData* currentRestyle = restylesToProcess;
           currentRestyle != lastRestyle;
           ++currentRestyle) {
        ProcessOneRestyle(currentRestyle->mElement,
                          currentRestyle->mRestyleHint,
                          currentRestyle->mChangeHint);
      }
    }
  }

  // Set mInStyleRefresh to false now, since the EndUpdate call might
  // add more restyles.
  mFrameConstructor->mInStyleRefresh = false;

  mFrameConstructor->EndUpdate();

#ifdef DEBUG
  mFrameConstructor->mPresShell->VerifyStyleTree();
#endif
}
Exemple #20
0
NS_IMETHODIMP nsViewManager::DispatchEvent(nsGUIEvent *aEvent,
                                           nsIView* aView, nsEventStatus *aStatus)
{
  NS_ASSERTION(!aView || static_cast<nsView*>(aView)->GetViewManager() == this,
               "wrong view manager");

  SAMPLE_LABEL("event", "nsViewManager::DispatchEvent");

  *aStatus = nsEventStatus_eIgnore;

  switch(aEvent->message)
    {
    case NS_SIZE:
      {
        if (aView)
          {
            // client area dimensions are set on the view
            nscoord width = ((nsSizeEvent*)aEvent)->windowSize->width;
            nscoord height = ((nsSizeEvent*)aEvent)->windowSize->height;

            // The root view may not be set if this is the resize associated with
            // window creation

            if (aView == mRootView)
              {
                PRInt32 p2a = AppUnitsPerDevPixel();
                SetWindowDimensions(NSIntPixelsToAppUnits(width, p2a),
                                    NSIntPixelsToAppUnits(height, p2a));
                *aStatus = nsEventStatus_eConsumeNoDefault;
              }
            else if (IsViewForPopup(aView))
              {
                nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
                if (pm)
                  {
                    pm->PopupResized(aView->GetFrame(), nsIntSize(width, height));
                    *aStatus = nsEventStatus_eConsumeNoDefault;
                  }
              }
          }
        }

        break;

    case NS_MOVE:
      {
        // A popup's parent view is the root view for the parent window, so when
        // a popup moves, the popup's frame and view position must be updated
        // to match.
        if (aView && IsViewForPopup(aView))
          {
            nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
            if (pm)
              {
                pm->PopupMoved(aView->GetFrame(), aEvent->refPoint);
                *aStatus = nsEventStatus_eConsumeNoDefault;
              }
          }
        break;
      }

    case NS_DONESIZEMOVE:
      {
        if (mPresShell) {
          nsPresContext* presContext = mPresShell->GetPresContext();
          if (presContext) {
            nsEventStateManager::ClearGlobalActiveContent(nsnull);
          }

        }

        nsIPresShell::ClearMouseCapture(nsnull);
      }
      break;
  
    case NS_XUL_CLOSE:
      {
        // if this is a popup, make a request to hide it. Note that a popuphidden
        // event listener may cancel the event and the popup will not be hidden.
        nsIWidget* widget = aView->GetWidget();
        if (widget) {
          nsWindowType type;
          widget->GetWindowType(type);
          if (type == eWindowType_popup) {
            nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
            if (pm) {
              pm->HidePopup(aView->GetFrame());
              *aStatus = nsEventStatus_eConsumeNoDefault;
            }
          }
        }
      }
      break;

    case NS_WILL_PAINT:
      {
        if (!aView || !mContext)
          break;

        *aStatus = nsEventStatus_eConsumeNoDefault;

        nsPaintEvent *event = static_cast<nsPaintEvent*>(aEvent);

        NS_ASSERTION(static_cast<nsView*>(aView) ==
                       nsView::GetViewFor(event->widget),
                     "view/widget mismatch");

        // If an ancestor widget was hidden and then shown, we could
        // have a delayed resize to handle.
        for (nsViewManager *vm = this; vm;
             vm = vm->mRootView->GetParent()
                    ? vm->mRootView->GetParent()->GetViewManager()
                    : nsnull) {
          if (vm->mDelayedResize != nsSize(NSCOORD_NONE, NSCOORD_NONE) &&
              vm->mRootView->IsEffectivelyVisible() &&
              mPresShell && mPresShell->IsVisible()) {
            vm->FlushDelayedResize(true);
            vm->InvalidateView(vm->mRootView);
          }
        }

        // Flush things like reflows and plugin widget geometry updates by
        // calling WillPaint on observer presShells.
        nsRefPtr<nsViewManager> rootVM = RootViewManager();
        if (mPresShell) {
          rootVM->CallWillPaintOnObservers(event->willSendDidPaint);
        }
        // Flush view widget geometry updates and invalidations.
        rootVM->ProcessPendingUpdates();
      }
      break;

    case NS_PAINT:
      {
        if (!aView || !mContext)
          break;

        *aStatus = nsEventStatus_eConsumeNoDefault;
        nsPaintEvent *event = static_cast<nsPaintEvent*>(aEvent);
        nsView* view = static_cast<nsView*>(aView);
        NS_ASSERTION(view == nsView::GetViewFor(event->widget),
                     "view/widget mismatch");
        NS_ASSERTION(IsPaintingAllowed(),
                     "shouldn't be receiving paint events while painting is "
                     "disallowed!");

        if (!event->didSendWillPaint) {
          // Send NS_WILL_PAINT event ourselves.
          nsPaintEvent willPaintEvent(true, NS_WILL_PAINT, event->widget);
          willPaintEvent.willSendDidPaint = event->willSendDidPaint;
          DispatchEvent(&willPaintEvent, view, aStatus);

          // Get the view pointer again since NS_WILL_PAINT might have
          // destroyed it during CallWillPaintOnObservers (bug 378273).
          view = nsView::GetViewFor(event->widget);
        }

        if (!view || event->region.IsEmpty())
          break;

        // Paint.
        Refresh(view, event->region, event->willSendDidPaint);

        break;
      }

    case NS_DID_PAINT: {
      nsRefPtr<nsViewManager> rootVM = RootViewManager();
      rootVM->CallDidPaintOnObserver();
      break;
    }

    case NS_CREATE:
    case NS_DESTROY:
    case NS_SETZLEVEL:
      /* Don't pass these events through. Passing them through
         causes performance problems on pages with lots of views/frames 
         @see bug 112861 */
      *aStatus = nsEventStatus_eConsumeNoDefault;
      break;

    case NS_DISPLAYCHANGED:

      //Destroy the cached backbuffer to force a new backbuffer
      //be constructed with the appropriate display depth.
      //@see bugzilla bug 6061
      *aStatus = nsEventStatus_eConsumeDoDefault;
      break;

    case NS_SYSCOLORCHANGED:
      {
        if (mPresShell) {
          // Hold a refcount to the presshell. The continued existence of the observer will
          // delay deletion of this view hierarchy should the event want to cause its
          // destruction in, say, some JavaScript event handler.
          nsCOMPtr<nsIPresShell> presShell = mPresShell;
          presShell->HandleEvent(aView->GetFrame(), aEvent, false, aStatus);
        }
      }
      break; 

    default:
      {
        if ((NS_IS_MOUSE_EVENT(aEvent) &&
             // Ignore mouse events that we synthesize.
             static_cast<nsMouseEvent*>(aEvent)->reason ==
               nsMouseEvent::eReal &&
             // Ignore mouse exit and enter (we'll get moves if the user
             // is really moving the mouse) since we get them when we
             // create and destroy widgets.
             aEvent->message != NS_MOUSE_EXIT &&
             aEvent->message != NS_MOUSE_ENTER) ||
            NS_IS_KEY_EVENT(aEvent) ||
            NS_IS_IME_EVENT(aEvent) ||
            aEvent->message == NS_PLUGIN_INPUT_EVENT) {
          gLastUserEventTime = PR_IntervalToMicroseconds(PR_IntervalNow());
        }

        if (aEvent->message == NS_DEACTIVATE) {
          // if a window is deactivated, clear the mouse capture regardless
          // of what is capturing
          nsIPresShell::ClearMouseCapture(nsnull);
        }

        // Find the view whose coordinates system we're in.
        nsIView* view = aView;
        bool dispatchUsingCoordinates = NS_IsEventUsingCoordinates(aEvent);
        if (dispatchUsingCoordinates) {
          // Will dispatch using coordinates. Pretty bogus but it's consistent
          // with what presshell does.
          view = GetDisplayRootFor(view);
        }
  
        // If the view has no frame, look for a view that does.
        nsIFrame* frame = view->GetFrame();
        if (!frame &&
            (dispatchUsingCoordinates || NS_IS_KEY_EVENT(aEvent) ||
             NS_IS_IME_RELATED_EVENT(aEvent) ||
             NS_IS_NON_RETARGETED_PLUGIN_EVENT(aEvent) ||
             aEvent->message == NS_PLUGIN_ACTIVATE ||
             aEvent->message == NS_PLUGIN_FOCUS)) {
          while (view && !view->GetFrame()) {
            view = view->GetParent();
          }

          if (view) {
            frame = view->GetFrame();
          }
        }

        if (nsnull != frame) {
          // Hold a refcount to the presshell. The continued existence of the
          // presshell will delay deletion of this view hierarchy should the event
          // want to cause its destruction in, say, some JavaScript event handler.
          nsCOMPtr<nsIPresShell> shell = view->GetViewManager()->GetPresShell();
          if (shell) {
            shell->HandleEvent(frame, aEvent, false, aStatus);
          }
        }
    
        break;
      }
    }

  return NS_OK;
}
Exemple #21
0
void
LayerManagerOGL::Render()
{
    SAMPLE_LABEL("LayerManagerOGL", "Render");
    if (mDestroyed) {
        NS_WARNING("Call on destroyed layer manager");
        return;
    }

    nsIntRect rect;
    mWidget->GetClientBounds(rect);
    WorldTransformRect(rect);

    GLint width = rect.width;
    GLint height = rect.height;

    // We can't draw anything to something with no area
    // so just return
    if (width == 0 || height == 0)
        return;

    // If the widget size changed, we have to force a MakeCurrent
    // to make sure that GL sees the updated widget size.
    if (mWidgetSize.width != width ||
            mWidgetSize.height != height)
    {
        MakeCurrent(true);

        mWidgetSize.width = width;
        mWidgetSize.height = height;
    } else {
        MakeCurrent();
    }

    SetupBackBuffer(width, height);
    SetupPipeline(width, height, ApplyWorldTransform);

    // Default blend function implements "OVER"
    mGLContext->fBlendFuncSeparate(LOCAL_GL_ONE, LOCAL_GL_ONE_MINUS_SRC_ALPHA,
                                   LOCAL_GL_ONE, LOCAL_GL_ONE);
    mGLContext->fEnable(LOCAL_GL_BLEND);

    const nsIntRect *clipRect = mRoot->GetClipRect();

    if (clipRect) {
        nsIntRect r = *clipRect;
        WorldTransformRect(r);
        mGLContext->fScissor(r.x, r.y, r.width, r.height);
    } else {
        mGLContext->fScissor(0, 0, width, height);
    }

    mGLContext->fEnable(LOCAL_GL_SCISSOR_TEST);

    mGLContext->fClearColor(0.0, 0.0, 0.0, 0.0);
    mGLContext->fClear(LOCAL_GL_COLOR_BUFFER_BIT | LOCAL_GL_DEPTH_BUFFER_BIT);

    // Render our layers.
    RootLayer()->RenderLayer(mGLContext->IsDoubleBuffered() ? 0 : mBackBufferFBO,
                             nsIntPoint(0, 0));

    mWidget->DrawWindowOverlay(this, rect);

#ifdef MOZ_DUMP_PAINTING
    if (gfxUtils::sDumpPainting) {
        nsIntRect rect;
        mWidget->GetBounds(rect);
        nsRefPtr<gfxASurface> surf = gfxPlatform::GetPlatform()->CreateOffscreenSurface(rect.Size(), gfxASurface::CONTENT_COLOR_ALPHA);
        nsRefPtr<gfxContext> ctx = new gfxContext(surf);
        CopyToTarget(ctx);

        WriteSnapshotToDumpFile(this, surf);
    }
#endif

    if (mTarget) {
        CopyToTarget(mTarget);
        mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0);
        return;
    }

    if (sDrawFPS) {
        mFPS.DrawFPS(mGLContext, GetCopy2DProgram());
    }

    if (mGLContext->IsDoubleBuffered()) {
        mGLContext->SwapBuffers();
        LayerManager::PostPresent();
        mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0);
        return;
    }

    mGLContext->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, 0);

    mGLContext->fActiveTexture(LOCAL_GL_TEXTURE0);

    CopyProgram *copyprog = GetCopy2DProgram();

    if (mFBOTextureTarget == LOCAL_GL_TEXTURE_RECTANGLE_ARB) {
        copyprog = GetCopy2DRectProgram();
    }

    mGLContext->fBindTexture(mFBOTextureTarget, mBackBufferTexture);

    copyprog->Activate();
    copyprog->SetTextureUnit(0);

    if (copyprog->GetTexCoordMultiplierUniformLocation() != -1) {
        float f[] = { float(width), float(height) };
        copyprog->SetUniform(copyprog->GetTexCoordMultiplierUniformLocation(),
                             2, f);
    }

    // we're going to use client-side vertex arrays for this.
    mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0);

    // "COPY"
    mGLContext->fBlendFuncSeparate(LOCAL_GL_ONE, LOCAL_GL_ZERO,
                                   LOCAL_GL_ONE, LOCAL_GL_ZERO);

    // enable our vertex attribs; we'll call glVertexPointer below
    // to fill with the correct data.
    GLint vcattr = copyprog->AttribLocation(CopyProgram::VertexCoordAttrib);
    GLint tcattr = copyprog->AttribLocation(CopyProgram::TexCoordAttrib);

    mGLContext->fEnableVertexAttribArray(vcattr);
    mGLContext->fEnableVertexAttribArray(tcattr);

    const nsIntRect *r;
    nsIntRegionRectIterator iter(mClippingRegion);

    while ((r = iter.Next()) != nsnull) {
        nsIntRect cRect = *r;
        r = &cRect;
        WorldTransformRect(cRect);
        float left = (GLfloat)r->x / width;
        float right = (GLfloat)r->XMost() / width;
        float top = (GLfloat)r->y / height;
        float bottom = (GLfloat)r->YMost() / height;

        float vertices[] = { left * 2.0f - 1.0f,
                             -(top * 2.0f - 1.0f),
                             right * 2.0f - 1.0f,
                             -(top * 2.0f - 1.0f),
                             left * 2.0f - 1.0f,
                             -(bottom * 2.0f - 1.0f),
                             right * 2.0f - 1.0f,
                             -(bottom * 2.0f - 1.0f)
                           };

        // Use flipped texture coordinates since our
        // projection matrix also has a flip and we
        // need to cancel that out.
        float coords[] = { left, bottom,
                           right, bottom,
                           left, top,
                           right, top
                         };

        mGLContext->fVertexAttribPointer(vcattr,
                                         2, LOCAL_GL_FLOAT,
                                         LOCAL_GL_FALSE,
                                         0, vertices);

        mGLContext->fVertexAttribPointer(tcattr,
                                         2, LOCAL_GL_FLOAT,
                                         LOCAL_GL_FALSE,
                                         0, coords);

        mGLContext->fDrawArrays(LOCAL_GL_TRIANGLE_STRIP, 0, 4);
    }

    mGLContext->fDisableVertexAttribArray(vcattr);
    mGLContext->fDisableVertexAttribArray(tcattr);

    mGLContext->fFlush();
    mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0);
}
Exemple #22
0
bool
ShadowLayerForwarder::EndTransaction(InfallibleTArray<EditReply>* aReplies)
{
  SAMPLE_LABEL("ShadowLayerForwarder", "EndTranscation");
  RenderTraceScope rendertrace("Foward Transaction", "000091");
  NS_ABORT_IF_FALSE(HasShadowManager(), "no manager to forward to");
  NS_ABORT_IF_FALSE(!mTxn->Finished(), "forgot BeginTransaction?");

  AutoTxnEnd _(mTxn);

  if (mTxn->Empty()) {
    MOZ_LAYERS_LOG(("[LayersForwarder] 0-length cset (?), skipping Update()"));
    return true;
  }

  MOZ_LAYERS_LOG(("[LayersForwarder] destroying buffers..."));

  for (PRUint32 i = 0; i < mTxn->mDyingBuffers.Length(); ++i) {
    DestroySharedSurface(&mTxn->mDyingBuffers[i]);
  }

  MOZ_LAYERS_LOG(("[LayersForwarder] building transaction..."));

  // We purposely add attribute-change ops to the final changeset
  // before we add paint ops.  This allows layers to record the
  // attribute changes before new pixels arrive, which can be useful
  // for setting up back/front buffers.
  RenderTraceScope rendertrace2("Foward Transaction", "000092");
  for (ShadowableLayerSet::const_iterator it = mTxn->mMutants.begin();
       it != mTxn->mMutants.end(); ++it) {
    ShadowableLayer* shadow = *it;
    Layer* mutant = shadow->AsLayer();
    NS_ABORT_IF_FALSE(!!mutant, "unshadowable layer?");

    LayerAttributes attrs;
    CommonLayerAttributes& common = attrs.common();
    common.visibleRegion() = mutant->GetVisibleRegion();
    common.transform() = mutant->GetTransform();
    common.contentFlags() = mutant->GetContentFlags();
    common.opacity() = mutant->GetOpacity();
    common.useClipRect() = !!mutant->GetClipRect();
    common.clipRect() = (common.useClipRect() ?
                         *mutant->GetClipRect() : nsIntRect());
    common.isFixedPosition() = mutant->GetIsFixedPosition();
    if (Layer* maskLayer = mutant->GetMaskLayer()) {
      common.maskLayerChild() = Shadow(maskLayer->AsShadowableLayer());
    } else {
      common.maskLayerChild() = NULL;
    }
    common.maskLayerParent() = NULL;
    attrs.specific() = null_t();
    mutant->FillSpecificAttributes(attrs.specific());

    mTxn->AddEdit(OpSetLayerAttributes(NULL, Shadow(shadow), attrs));
  }

  AutoInfallibleTArray<Edit, 10> cset;
  size_t nCsets = mTxn->mCset.size() + mTxn->mPaints.size();
  NS_ABORT_IF_FALSE(nCsets > 0, "should have bailed by now");

  cset.SetCapacity(nCsets);
  if (!mTxn->mCset.empty()) {
    cset.AppendElements(&mTxn->mCset.front(), mTxn->mCset.size());
  }
  // Paints after non-paint ops, including attribute changes.  See
  // above.
  if (!mTxn->mPaints.empty()) {
    cset.AppendElements(&mTxn->mPaints.front(), mTxn->mPaints.size());
  }

  MOZ_LAYERS_LOG(("[LayersForwarder] syncing before send..."));
  PlatformSyncBeforeUpdate();

  if (mTxn->mSwapRequired) {
    MOZ_LAYERS_LOG(("[LayersForwarder] sending transaction..."));
    RenderTraceScope rendertrace3("Forward Transaction", "000093");
    if (!mShadowManager->SendUpdate(cset, mIsFirstPaint, aReplies)) {
      MOZ_LAYERS_LOG(("[LayersForwarder] WARNING: sending transaction failed!"));
      return false;
    }
  } else {
    // If we don't require a swap we can call SendUpdateNoSwap which
    // assumes that aReplies is empty (DEBUG assertion)
    MOZ_LAYERS_LOG(("[LayersForwarder] sending no swap transaction..."));
    RenderTraceScope rendertrace3("Forward NoSwap Transaction", "000093");
    if (!mShadowManager->SendUpdateNoSwap(cset, mIsFirstPaint)) {
      MOZ_LAYERS_LOG(("[LayersForwarder] WARNING: sending transaction failed!"));
      return false;
    }
  }

  mIsFirstPaint = false;
  MOZ_LAYERS_LOG(("[LayersForwarder] ... done"));
  return true;
}
NS_IMETHODIMP
nsPluginStreamListenerPeer::OnStartRequest(nsIRequest *request,
        nsISupports* aContext)
{
    nsresult rv = NS_OK;
    SAMPLE_LABEL("nsPluginStreamListenerPeer", "OnStartRequest");

    if (mRequests.IndexOfObject(GetBaseRequest(request)) == -1) {
        NS_ASSERTION(mRequests.Count() == 0,
                     "Only our initial stream should be unknown!");
        TrackRequest(request);
    }

    if (mHaveFiredOnStartRequest) {
        return NS_OK;
    }

    mHaveFiredOnStartRequest = true;

    nsCOMPtr<nsIChannel> channel = do_QueryInterface(request);
    NS_ENSURE_TRUE(channel, NS_ERROR_FAILURE);

    // deal with 404 (Not Found) HTTP response,
    // just return, this causes the request to be ignored.
    nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(channel));
    if (httpChannel) {
        uint32_t responseCode = 0;
        rv = httpChannel->GetResponseStatus(&responseCode);
        if (NS_FAILED(rv)) {
            // NPP_Notify() will be called from OnStopRequest
            // in nsNPAPIPluginStreamListener::CleanUpStream
            // return error will cancel this request
            // ...and we also need to tell the plugin that
            mRequestFailed = true;
            return NS_ERROR_FAILURE;
        }

        if (responseCode > 206) { // not normal
            uint32_t wantsAllNetworkStreams = 0;

            // We don't always have an instance here already, but if we do, check
            // to see if it wants all streams.
            if (mPluginInstance) {
                rv = mPluginInstance->GetValueFromPlugin(NPPVpluginWantsAllNetworkStreams,
                        &wantsAllNetworkStreams);
                // If the call returned an error code make sure we still use our default value.
                if (NS_FAILED(rv)) {
                    wantsAllNetworkStreams = 0;
                }
            }

            if (!wantsAllNetworkStreams) {
                mRequestFailed = true;
                return NS_ERROR_FAILURE;
            }
        }
    }

    // Get the notification callbacks from the channel and save it as
    // week ref we'll use it in nsPluginStreamInfo::RequestRead() when
    // we'll create channel for byte range request.
    nsCOMPtr<nsIInterfaceRequestor> callbacks;
    channel->GetNotificationCallbacks(getter_AddRefs(callbacks));
    if (callbacks)
        mWeakPtrChannelCallbacks = do_GetWeakReference(callbacks);

    nsCOMPtr<nsILoadGroup> loadGroup;
    channel->GetLoadGroup(getter_AddRefs(loadGroup));
    if (loadGroup)
        mWeakPtrChannelLoadGroup = do_GetWeakReference(loadGroup);

    int64_t length;
    rv = channel->GetContentLength(&length);

    // it's possible for the server to not send a Content-Length.
    // we should still work in this case.
    if (NS_FAILED(rv) || length == -1) {
        // check out if this is file channel
        nsCOMPtr<nsIFileChannel> fileChannel = do_QueryInterface(channel);
        if (fileChannel) {
            // file does not exist
            mRequestFailed = true;
            return NS_ERROR_FAILURE;
        }
        mLength = 0;
    }
    else {
        mLength = length;
    }

    nsAutoCString aContentType; // XXX but we already got the type above!
    rv = channel->GetContentType(aContentType);
    if (NS_FAILED(rv))
        return rv;

    nsCOMPtr<nsIURI> aURL;
    rv = channel->GetURI(getter_AddRefs(aURL));
    if (NS_FAILED(rv))
        return rv;

    aURL->GetSpec(mURLSpec);

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

#ifdef PLUGIN_LOGGING
    PR_LOG(nsPluginLogging::gPluginLog, PLUGIN_LOG_NOISY,
           ("nsPluginStreamListenerPeer::OnStartRequest this=%p request=%p mime=%s, url=%s\n",
            this, request, aContentType.get(), mURLSpec.get()));

    PR_LogFlush();
#endif

    // Set up the stream listener...
    rv = SetUpStreamListener(request, aURL);
    if (NS_FAILED(rv)) return rv;

    return rv;
}
PRUint32
nsInputStreamPump::OnStateTransfer()
{
    SAMPLE_LABEL("Input", "nsInputStreamPump::OnStateTransfer");
    LOG(("  OnStateTransfer [this=%x]\n", this));

    // if canceled, go directly to STATE_STOP...
    if (NS_FAILED(mStatus))
        return STATE_STOP;

    nsresult rv;

    PRUint32 avail;
    rv = mAsyncStream->Available(&avail);
    LOG(("  Available returned [stream=%x rv=%x avail=%u]\n", mAsyncStream.get(), rv, avail));

    if (rv == NS_BASE_STREAM_CLOSED) {
        rv = NS_OK;
        avail = 0;
    }
    else if (NS_SUCCEEDED(rv) && avail) {
        // figure out how much data to report (XXX detect overflow??)
        if (PRUint64(avail) + mStreamOffset > mStreamLength)
            avail = PRUint32(mStreamLength - mStreamOffset);

        if (avail) {
            // we used to limit avail to 16K - we were afraid some ODA handlers
            // might assume they wouldn't get more than 16K at once
            // we're removing that limit since it speeds up local file access.
            // Now there's an implicit 64K limit of 4 16K segments
            // NOTE: ok, so the story is as follows.  OnDataAvailable impls
            //       are by contract supposed to consume exactly |avail| bytes.
            //       however, many do not... mailnews... stream converters...
            //       cough, cough.  the input stream pump is fairly tolerant
            //       in this regard; however, if an ODA does not consume any
            //       data from the stream, then we could potentially end up in
            //       an infinite loop.  we do our best here to try to catch
            //       such an error.  (see bug 189672)

            // in most cases this QI will succeed (mAsyncStream is almost always
            // a nsPipeInputStream, which implements nsISeekableStream::Tell).
            PRInt64 offsetBefore;
            nsCOMPtr<nsISeekableStream> seekable = do_QueryInterface(mAsyncStream);
            if (seekable && NS_FAILED(seekable->Tell(&offsetBefore))) {
                NS_NOTREACHED("Tell failed on readable stream");
                offsetBefore = 0;
            }

            // report the current stream offset to our listener... if we've
            // streamed more than PR_UINT32_MAX, then avoid overflowing the
            // stream offset.  it's the best we can do without a 64-bit stream
            // listener API.
            PRUint32 odaOffset =
                mStreamOffset > PR_UINT32_MAX ?
                PR_UINT32_MAX : PRUint32(mStreamOffset);

            LOG(("  calling OnDataAvailable [offset=%lld(%u) count=%u]\n",
                mStreamOffset, odaOffset, avail));

            rv = mListener->OnDataAvailable(this, mListenerContext, mAsyncStream,
                                            odaOffset, avail);

            // don't enter this code if ODA failed or called Cancel
            if (NS_SUCCEEDED(rv) && NS_SUCCEEDED(mStatus)) {
                // test to see if this ODA failed to consume data
                if (seekable) {
                    // NOTE: if Tell fails, which can happen if the stream is
                    // now closed, then we assume that everything was read.
                    PRInt64 offsetAfter;
                    if (NS_FAILED(seekable->Tell(&offsetAfter)))
                        offsetAfter = offsetBefore + avail;
                    if (offsetAfter > offsetBefore)
                        mStreamOffset += (offsetAfter - offsetBefore);
                    else if (mSuspendCount == 0) {
                        //
                        // possible infinite loop if we continue pumping data!
                        //
                        // NOTE: although not allowed by nsIStreamListener, we
                        // will allow the ODA impl to Suspend the pump.  IMAP
                        // does this :-(
                        //
                        NS_ERROR("OnDataAvailable implementation consumed no data");
                        mStatus = NS_ERROR_UNEXPECTED;
                    }
                }
                else
                    mStreamOffset += avail; // assume ODA behaved well
            }
        }
    }

    // an error returned from Available or OnDataAvailable should cause us to
    // abort; however, we must not stomp on mStatus if already canceled.

    if (NS_SUCCEEDED(mStatus)) {
        if (NS_FAILED(rv))
            mStatus = rv;
        else if (avail) {
            // if stream is now closed, advance to STATE_STOP right away.
            // Available may return 0 bytes available at the moment; that
            // would not mean that we are done.
            // XXX async streams should have a GetStatus method!
            rv = mAsyncStream->Available(&avail);
            if (NS_SUCCEEDED(rv))
                return STATE_TRANSFER;
        }
    }
    return STATE_STOP;
}