Ejemplo n.º 1
0
void
MediaSourceImpl::EnsureBuffering()
{
	switch (EnsureBufferingInternal())
	{
	case NONE:
		break;
	case STARTED:
		m_state = STARTED;
		break;
	case IDLE:
		if (VerifyContentType())
		{
			m_state = IDLE;
			for (OpListenersIterator iter(m_listeners); m_listeners.HasNext(iter);)
				m_listeners.GetNext(iter)->OnIdle(this);
		}
		else
		{
			OP_ASSERT(m_state == FAILED);
		}
		break;
	case FAILED:
		LoadFailed();
		break;
	default:
		OP_ASSERT(!"Unexpected state change");
	}
}
Ejemplo n.º 2
0
/* virtual */ void
MediaSourceImpl::HandleCallback(OpMessage msg, MH_PARAM_1 par1, MH_PARAM_2 par2)
{
	if (msg == MSG_MEDIA_SOURCE_ENSURE_BUFFERING)
	{
		OP_ASSERT(m_pending_ensure);
		EnsureBuffering();
		m_pending_ensure = FALSE;
		return;
	}
	else if (msg == MSG_MEDIA_SOURCE_NOTIFY_LISTENER)
	{
		// The listener may have been removed while the message was
		// pending, so find it in the listeners list before notifying.
		MediaProgressListener* listener = reinterpret_cast<MediaProgressListener*>(par2);
		for (OpListenersIterator iter(m_listeners); m_listeners.HasNext(iter);)
		{
			if (m_listeners.GetNext(iter) == listener)
			{
				if (m_state == FAILED)
					listener->OnError(this);
				else if (m_state == IDLE)
					listener->OnIdle(this);
				// else: The state has already changed and the
				// listener was notified just like the others.
				break;
			}
		}
		return;
	}

	// URL_DataDescriptor::RetrieveData posts MSG_URL_DATA_LOADED when
	// reading, which we are not interested in when idle or paused.
	// URL messages after an error are irrelevant to us.
	if (m_state == IDLE || m_state == PAUSED || m_state == FAILED)
		return;

	// URL messages in the message queue when calling StopLoading
	// will arrive after starting a new request, at which point they
	// must be ignored. Wait for headers/failure/redirect.
	if (m_state == STARTED && msg == MSG_URL_DATA_LOADED)
		return;

	OP_ASSERT(m_state == STARTED || m_state == HEADERS || m_state == LOADING);
	switch(msg)
	{
	case MSG_HEADER_LOADED:
		OP_ASSERT(m_state == STARTED);
		m_state = HEADERS;
		// If we are streaming, tell all listeners except the first to
		// restart loading, at which point they'll get a new source.
		if (IsStreaming())
		{
			OpListenersIterator iter(m_listeners);
			m_listeners.GetNext(iter);
			while (m_listeners.HasNext(iter))
				m_listeners.GetNext(iter)->OnClientCollision(this);
		}
		break;
	case MSG_URL_DATA_LOADED:
		if (m_state == HEADERS)
			m_state = LOADING;
		OP_ASSERT(m_state == LOADING);
		if (IsSuccessURL(m_use_url))
		{
			// This point will be reached very often while the
			// transfer is progressing normally, so it is important
			// that the following steps are not needlessly wasteful.

			if (!VerifyContentType())
				return;

			// EnsureBuffering does a non-trivial amount of work, so
			// only call it if (a) the request has finished or (b) the
			// current request is "too big" and needs clamping.
			if (m_clamp_request || IsLoadedURL(m_use_url))
			{
				EnsureBuffering();
				if (m_state != LOADING)
					break;
			}

			// The listeners are responsible for throttling the
			// side-effects buffering progress.
			for (OpListenersIterator iter(m_listeners); m_listeners.HasNext(iter);)
				m_listeners.GetNext(iter)->OnProgress(this);

			if (IsStreaming())
			{
				BOOL available;
				OpFileLength remaining;
				GetStreamingCoverage(available, remaining);
				if (available && remaining < STREAMING_CACHE_PAUSE_LIMIT)
					PauseBuffering();
			}
		}
		else
		{
			LoadFailed();
		}
		break;
	case MSG_URL_LOADING_FAILED:
		// Try to recover from a network errors that happen while
		// loading, but not those that happen before (or after) that.
		if (m_state == LOADING && IsResumableURL(m_use_url))
		{
			StopBuffering();
			m_state = IDLE;
			EnsureBuffering();
		}
		else
		{
			LoadFailed();
		}
		break;
	case MSG_URL_MOVED:
		{
			URL moved_to = m_use_url->GetAttribute(URL::KMovedToURL, URL::KFollowRedirect);
			if (!moved_to.IsEmpty())
			{
				OP_ASSERT(m_use_url->Id(URL::KFollowRedirect) == (URL_ID)par2 &&
						  moved_to.Id(URL::KNoRedirect) == (URL_ID)par2);
				m_use_url.SetURL(moved_to);
				OP_DELETE(m_url_dd);
				m_url_dd = NULL;
				m_message_handler->UnsetCallBacks(this);
				RAISE_AND_RETURN_VOID_IF_ERROR(SetCallBacks());
			}
		}
		break;
	default:
		OP_ASSERT(FALSE);
	}

	// Ensure that we are notified of further buffering progress.
	if (m_url_dd)
		m_url_dd->ClearPostedMessage();
}
Ejemplo n.º 3
0
void
ThebesLayerD3D10::Validate(ReadbackProcessor *aReadback)
{
  if (mVisibleRegion.IsEmpty()) {
    return;
  }

  nsIntRect newTextureRect = mVisibleRegion.GetBounds();

  SurfaceMode mode = GetSurfaceMode();
  if (mode == SURFACE_COMPONENT_ALPHA &&
      (!mParent || !mParent->SupportsComponentAlphaChildren())) {
    mode = SURFACE_SINGLE_CHANNEL_ALPHA;
  }
  // If we have a transform that requires resampling of our texture, then
  // we need to make sure we don't sample pixels that haven't been drawn.
  // We clamp sample coordinates to the texture rect, but when the visible region
  // doesn't fill the entire texture rect we need to make sure we draw all the
  // pixels in the texture rect anyway in case they get sampled.
  nsIntRegion neededRegion = mVisibleRegion;
  if (!neededRegion.GetBounds().IsEqualInterior(newTextureRect) ||
      neededRegion.GetNumRects() > 1) {
    gfxMatrix transform2d;
    if (!GetEffectiveTransform().Is2D(&transform2d) ||
        transform2d.HasNonIntegerTranslation()) {
      neededRegion = newTextureRect;
      if (mode == SURFACE_OPAQUE) {
        // We're going to paint outside the visible region, but layout hasn't
        // promised that it will paint opaquely there, so we'll have to
        // treat this layer as transparent.
        mode = SURFACE_SINGLE_CHANNEL_ALPHA;
      }
    }
  }
  mCurrentSurfaceMode = mode;

  VerifyContentType(mode);

  nsTArray<ReadbackProcessor::Update> readbackUpdates;
  nsIntRegion readbackRegion;
  if (aReadback && UsedForReadback()) {
    aReadback->GetThebesLayerUpdates(this, &readbackUpdates, &readbackRegion);
  }

  if (mTexture) {
    if (!mTextureRect.IsEqualInterior(newTextureRect)) {
      nsRefPtr<ID3D10Texture2D> oldTexture = mTexture;
      mTexture = nullptr;
      nsRefPtr<ID3D10Texture2D> oldTextureOnWhite = mTextureOnWhite;
      mTextureOnWhite = nullptr;

      nsIntRegion retainRegion = mTextureRect;
      // Old visible region will become the region that is covered by both the
      // old and the new visible region.
      retainRegion.And(retainRegion, mVisibleRegion);
      // No point in retaining parts which were not valid.
      retainRegion.And(retainRegion, mValidRegion);

      CreateNewTextures(gfxIntSize(newTextureRect.width, newTextureRect.height), mode);

      nsIntRect largeRect = retainRegion.GetLargestRectangle();

      // If we had no hardware texture before, or have no retained area larger than
      // the retention threshold, we're not retaining and are done here.
      // If our texture creation failed this can mean a device reset is pending
      // and we should silently ignore the failure. In the future when device
      // failures are properly handled we should test for the type of failure
      // and gracefully handle different failures. See bug 569081.
      if (!oldTexture || !mTexture ||
          largeRect.width * largeRect.height < RETENTION_THRESHOLD) {
        mValidRegion.SetEmpty();
      } else {
        CopyRegion(oldTexture, mTextureRect.TopLeft(),
                   mTexture, newTextureRect.TopLeft(),
                   retainRegion, &mValidRegion);
        if (oldTextureOnWhite) {
          CopyRegion(oldTextureOnWhite, mTextureRect.TopLeft(),
                     mTextureOnWhite, newTextureRect.TopLeft(),
                     retainRegion, &mValidRegion);
        }
      }
    }
  }
  mTextureRect = newTextureRect;

  if (!mTexture || (mode == SURFACE_COMPONENT_ALPHA && !mTextureOnWhite)) {
    CreateNewTextures(gfxIntSize(newTextureRect.width, newTextureRect.height), mode);
    mValidRegion.SetEmpty();
  }

  nsIntRegion drawRegion;
  drawRegion.Sub(neededRegion, mValidRegion);

  if (!drawRegion.IsEmpty()) {
    LayerManagerD3D10::CallbackInfo cbInfo = mD3DManager->GetCallbackInfo();
    if (!cbInfo.Callback) {
      NS_ERROR("D3D10 should never need to update ThebesLayers in an empty transaction");
      return;
    }

    DrawRegion(drawRegion, mode);

    if (readbackUpdates.Length() > 0) {
      CD3D10_TEXTURE2D_DESC desc(DXGI_FORMAT_B8G8R8A8_UNORM,
                                 newTextureRect.width, newTextureRect.height,
                                 1, 1, 0, D3D10_USAGE_STAGING,
                                 D3D10_CPU_ACCESS_READ);

      nsRefPtr<ID3D10Texture2D> readbackTexture;
      HRESULT hr = device()->CreateTexture2D(&desc, NULL, getter_AddRefs(readbackTexture));
      if (FAILED(hr)) {
        LayerManagerD3D10::ReportFailure(NS_LITERAL_CSTRING("ThebesLayerD3D10::Validate(): Failed to create texture"),
                                         hr);
        return;
      }

      device()->CopyResource(readbackTexture, mTexture);

      for (uint32_t i = 0; i < readbackUpdates.Length(); i++) {
        mD3DManager->readbackManager()->PostTask(readbackTexture,
                                                 &readbackUpdates[i],
                                                 gfxPoint(newTextureRect.x, newTextureRect.y));
      }
    }

    mValidRegion = neededRegion;
  }
}