Пример #1
0
RasterImage::Draw(gfxContext* aContext,
                  const IntSize& aSize,
                  const ImageRegion& aRegion,
                  uint32_t aWhichFrame,
                  SamplingFilter aSamplingFilter,
                  const Maybe<SVGImageContext>& /*aSVGContext - ignored*/,
                  uint32_t aFlags,
                  float aOpacity)
{
  if (aWhichFrame > FRAME_MAX_VALUE) {
    return DrawResult::BAD_ARGS;
  }

  if (mError) {
    return DrawResult::BAD_IMAGE;
  }

  // Illegal -- you can't draw with non-default decode flags.
  // (Disabling colorspace conversion might make sense to allow, but
  // we don't currently.)
  if (ToSurfaceFlags(aFlags) != DefaultSurfaceFlags()) {
    return DrawResult::BAD_ARGS;
  }

  if (!aContext) {
    return DrawResult::BAD_ARGS;
  }

  if (IsUnlocked()) {
    SendOnUnlockedDraw(aFlags);
  }


  // If we're not using SamplingFilter::GOOD, we shouldn't high-quality scale or
  // downscale during decode.
  uint32_t flags = aSamplingFilter == SamplingFilter::GOOD
                 ? aFlags
                 : aFlags & ~FLAG_HIGH_QUALITY_SCALING;

  DrawableSurface surface =
    LookupFrame(aSize, flags, ToPlaybackType(aWhichFrame));
  if (!surface) {
    // Getting the frame (above) touches the image and kicks off decoding.
    if (mDrawStartTime.IsNull()) {
      mDrawStartTime = TimeStamp::Now();
    }
    return DrawResult::NOT_READY;
  }

  bool shouldRecordTelemetry = !mDrawStartTime.IsNull() &&
                               surface->IsFinished();

  auto result = DrawInternal(Move(surface), aContext, aSize,
                             aRegion, aSamplingFilter, flags, aOpacity);

  if (shouldRecordTelemetry) {
      TimeDuration drawLatency = TimeStamp::Now() - mDrawStartTime;
      Telemetry::Accumulate(Telemetry::IMAGE_DECODE_ON_DRAW_LATENCY,
                            int32_t(drawLatency.ToMicroseconds()));
      mDrawStartTime = TimeStamp();
  }

  return result;
}
Пример #2
0
nsresult
PrincipalToPrincipalInfo(nsIPrincipal* aPrincipal,
                         PrincipalInfo* aPrincipalInfo)
{
  MOZ_ASSERT(NS_IsMainThread());
  MOZ_ASSERT(aPrincipal);
  MOZ_ASSERT(aPrincipalInfo);

  bool isNullPointer;
  nsresult rv = aPrincipal->GetIsNullPrincipal(&isNullPointer);
  if (NS_WARN_IF(NS_FAILED(rv))) {
    return rv;
  }

  if (isNullPointer) {
    *aPrincipalInfo = NullPrincipalInfo();
    return NS_OK;
  }

  nsCOMPtr<nsIScriptSecurityManager> secMan =
    do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv);
  if (NS_WARN_IF(NS_FAILED(rv))) {
    return rv;
  }

  bool isSystemPrincipal;
  rv = secMan->IsSystemPrincipal(aPrincipal, &isSystemPrincipal);
  if (NS_WARN_IF(NS_FAILED(rv))) {
    return rv;
  }

  if (isSystemPrincipal) {
    *aPrincipalInfo = SystemPrincipalInfo();
    return NS_OK;
  }

  // might be an expanded principal
  nsCOMPtr<nsIExpandedPrincipal> expanded =
    do_QueryInterface(aPrincipal);

  if (expanded) {
    nsTArray<PrincipalInfo> whitelistInfo;
    PrincipalInfo info;

    nsTArray< nsCOMPtr<nsIPrincipal> >* whitelist;
    MOZ_ALWAYS_TRUE(NS_SUCCEEDED(expanded->GetWhiteList(&whitelist)));

    for (uint32_t i = 0; i < whitelist->Length(); i++) {
      rv = PrincipalToPrincipalInfo((*whitelist)[i], &info);
      if (NS_WARN_IF(NS_FAILED(rv))) {
        return rv;
      }
      // append that spec to the whitelist
      whitelistInfo.AppendElement(info);
    }

    *aPrincipalInfo = ExpandedPrincipalInfo(Move(whitelistInfo));
    return NS_OK;
  }

  // must be a content principal

  nsCOMPtr<nsIURI> uri;
  rv = aPrincipal->GetURI(getter_AddRefs(uri));
  if (NS_WARN_IF(NS_FAILED(rv))) {
    return rv;
  }

  if (NS_WARN_IF(!uri)) {
    return NS_ERROR_FAILURE;
  }

  nsCString spec;
  rv = uri->GetSpec(spec);
  if (NS_WARN_IF(NS_FAILED(rv))) {
    return rv;
  }

  *aPrincipalInfo = ContentPrincipalInfo(BasePrincipal::Cast(aPrincipal)->OriginAttributesRef(),
                                         spec);
  return NS_OK;
}
Пример #3
0
nsresult
AppleATDecoder::DecodeSample(MediaRawData* aSample)
{
  MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn());

  // Array containing the queued decoded audio frames, about to be output.
  nsTArray<AudioDataValue> outputData;
  UInt32 channels = mOutputFormat.mChannelsPerFrame;
  // Pick a multiple of the frame size close to a power of two
  // for efficient allocation.
  const uint32_t MAX_AUDIO_FRAMES = 128;
  const uint32_t maxDecodedSamples = MAX_AUDIO_FRAMES * channels;

  // Descriptions for _decompressed_ audio packets. ignored.
  auto packets = MakeUnique<AudioStreamPacketDescription[]>(MAX_AUDIO_FRAMES);

  // This API insists on having packets spoon-fed to it from a callback.
  // This structure exists only to pass our state.
  PassthroughUserData userData =
    { channels, (UInt32)aSample->Size(), aSample->Data() };

  // Decompressed audio buffer
  AlignedAudioBuffer decoded(maxDecodedSamples);
  if (!decoded) {
    return NS_ERROR_OUT_OF_MEMORY;
  }

  do {
    AudioBufferList decBuffer;
    decBuffer.mNumberBuffers = 1;
    decBuffer.mBuffers[0].mNumberChannels = channels;
    decBuffer.mBuffers[0].mDataByteSize =
      maxDecodedSamples * sizeof(AudioDataValue);
    decBuffer.mBuffers[0].mData = decoded.get();

    // in: the max number of packets we can handle from the decoder.
    // out: the number of packets the decoder is actually returning.
    UInt32 numFrames = MAX_AUDIO_FRAMES;

    OSStatus rv = AudioConverterFillComplexBuffer(mConverter,
                                                  _PassthroughInputDataCallback,
                                                  &userData,
                                                  &numFrames /* in/out */,
                                                  &decBuffer,
                                                  packets.get());

    if (rv && rv != kNoMoreDataErr) {
      LOG("Error decoding audio stream: %d\n", rv);
      return NS_ERROR_FAILURE;
    }

    if (numFrames) {
      outputData.AppendElements(decoded.get(), numFrames * channels);
    }

    if (rv == kNoMoreDataErr) {
      break;
    }
  } while (true);

  if (outputData.IsEmpty()) {
    return NS_OK;
  }

  size_t numFrames = outputData.Length() / channels;
  int rate = mOutputFormat.mSampleRate;
  media::TimeUnit duration = FramesToTimeUnit(numFrames, rate);
  if (!duration.IsValid()) {
    NS_WARNING("Invalid count of accumulated audio samples");
    return NS_ERROR_FAILURE;
  }

#ifdef LOG_SAMPLE_DECODE
  LOG("pushed audio at time %lfs; duration %lfs\n",
      (double)aSample->mTime / USECS_PER_S,
      duration.ToSeconds());
#endif

  AudioSampleBuffer data(outputData.Elements(), outputData.Length());
  if (!data.Data()) {
    return NS_ERROR_OUT_OF_MEMORY;
  }
  if (mChannelLayout && !mAudioConverter) {
    AudioConfig in(*mChannelLayout.get(), rate);
    AudioConfig out(channels, rate);
    if (!in.IsValid() || !out.IsValid()) {
      return NS_ERROR_FAILURE;
    }
    mAudioConverter = MakeUnique<AudioConverter>(in, out);
  }
  if (mAudioConverter) {
    MOZ_ASSERT(mAudioConverter->CanWorkInPlace());
    data = mAudioConverter->Process(Move(data));
  }

  RefPtr<AudioData> audio = new AudioData(aSample->mOffset,
                                          aSample->mTime,
                                          duration.ToMicroseconds(),
                                          numFrames,
                                          data.Forget(),
                                          channels,
                                          rate);
  mCallback->Output(audio);
  return NS_OK;
}
Пример #4
0
// start dragging. This is the only routine exposed externally. 
// pt = mouse position at start of drag (screen co-ords) 
void COXDragDockContext::StartDrag(CPoint pt)
{
   	ASSERT_VALID(m_pBar);
   	ASSERT(m_pBar->IsKindOf(RUNTIME_CLASS(COXSizeControlBar)));

   	COXSizeControlBar* pSzBar = (COXSizeControlBar*)m_pBar;

    // get styles from bar
   	m_dwDockStyle = m_pBar->m_dwDockStyle;
   	m_dwStyle = m_pBar->m_dwStyle & CBRS_ALIGN_ANY;
   	ASSERT(m_dwStyle != 0);
	
	// check to see we're not hanging from a COXMDIFloatWnd. 
	// Disallow dragging if we are...
	if (m_pBar->IsFloating())
	{
		CFrameWnd* pFrameWnd = m_pBar->GetParentFrame();
		ASSERT(pFrameWnd != NULL);
		ASSERT(pFrameWnd->IsKindOf(RUNTIME_CLASS(CFrameWnd)));
		if (pFrameWnd->IsKindOf(RUNTIME_CLASS(COXMDIFloatWnd)))
			return;				// do nothing if floating inside a COXMDIFloatWnd
	}
	
	// dragging has started message (only if window will actually dock !)
    if ((m_dwDockStyle & CBRS_ALIGN_ANY) == CBRS_ALIGN_ANY)
		AfxGetMainWnd()->SendMessage(WM_SETMESSAGESTRING, IDS_OX_MRC_STARTDOCKING);
	
    // handle pending WM_PAINT messages
    MSG msg;
    while (::PeekMessage(&msg, NULL, WM_PAINT, WM_PAINT, PM_NOREMOVE))
	{
		if (!GetMessage(&msg, NULL, WM_PAINT, WM_PAINT))
			return;
		ASSERT(msg.message == WM_PAINT);
        DispatchMessage(&msg);
	}
	
    // initialize drag state
   	m_rectLast.SetRectEmpty();
   	m_sizeLast.cx = m_sizeLast.cy = 0;
   	m_bForceFrame = m_bFlip = m_bDitherLast = FALSE;
	
	
   	// get current bar location 
   	CRect rect;
   	m_pBar->GetWindowRect(rect);
   	m_ptLast = pt;
   	m_ptStart = pt;
	BOOL bHorz = HORZF(m_dwStyle);
	
   	// MFC includes code for flipping orientation using the shift key - I wasn't keen
	// on this... (sorry) so I've left it out for now. Some references are still left
	// in for it, in case I decide to implement it.
   	
   	// Start by working out the possible rectangles that dragging could result in.
	// These are:
	// m_rectFrameDragHorz	: floating frame, horizontal orientation
	// m_rectFrameDragVert	: floating frame, vertical orientation (not used, 'cos
	//									flipping not allowed)
	//
	// m_rectDragHorz		: docking horizontally, another bar already on this row
	// m_rectDragVert		: docking vertically, another bar already on this row
	
	// m_rectDragHorzAlone  : docking horizontally, on a new row
	// m_rectDragVertAlone  : docking vertically, on a new row
	
	
	// calculate dragging rects if you drag on the new row/column
	//
	CRect rectBorder;
	m_pDockSite->RepositionBars(0,0xffff,AFX_IDW_PANE_FIRST, 
		CFrameWnd::reposQuery,&rectBorder);
	m_pDockSite->ClientToScreen(rectBorder);
	CWnd* pLeftDockBar=m_pDockSite->GetControlBar(AFX_IDW_DOCKBAR_LEFT);
	if(pLeftDockBar!=NULL && pLeftDockBar->GetStyle()&WS_VISIBLE)
	{
		CRect rectDockBar;
		pLeftDockBar->GetWindowRect(rectDockBar);
		rectBorder.left-=rectDockBar.Width();
	}
	CWnd* pRightDockBar=m_pDockSite->GetControlBar(AFX_IDW_DOCKBAR_RIGHT);
	if(pRightDockBar!=NULL && pRightDockBar->GetStyle()&WS_VISIBLE)
	{
		CRect rectDockBar;
		pRightDockBar->GetWindowRect(rectDockBar);
		rectBorder.right+=rectDockBar.Width();
	}
	m_rectDragHorzAlone=CRect(CPoint(rectBorder.left,rect.top),rectBorder.Size());
	m_rectDragVertAlone=CRect(CPoint(rect.left,rectBorder.top),rectBorder.Size());
	m_rectDragHorzAlone.bottom=m_rectDragHorzAlone.top+pSzBar->m_HorzDockSize.cy;
	m_rectDragVertAlone.right=m_rectDragVertAlone.left+pSzBar->m_VertDockSize.cx;
	//
	//////////////////////////////////////////////////////////////


	//////////////////
	//
	int nDockAreaWidth = rectBorder.Width();
	int nDockAreaHeight = rectBorder.Height();

	CSize HorzAloneSize(nDockAreaWidth, pSzBar->m_HorzDockSize.cy);
	CSize VertAloneSize(pSzBar->m_VertDockSize.cx, nDockAreaHeight);
	
	// sizes to use when docking into a row that already has some bars.
	// use the stored sizes - unless they are > the max dock area - 
	// in which case make a guess.
	if (pSzBar->m_VertDockSize.cy >= nDockAreaHeight - 16)
		VertAloneSize.cy = nDockAreaHeight / 3;
	else 
		VertAloneSize.cy = pSzBar->m_VertDockSize.cy;
	
	if (pSzBar->m_HorzDockSize.cx >= nDockAreaWidth - 16)
		HorzAloneSize.cx = nDockAreaWidth / 3;
	else
		HorzAloneSize.cx = pSzBar->m_HorzDockSize.cx;
	

	m_rectDragHorz = CRect(rect.TopLeft(), HorzAloneSize);
	m_rectDragVert = CRect(rect.TopLeft(), VertAloneSize);
	//
	///////////////////


   	// rectangle for the floating frame...
   	m_rectFrameDragVert = m_rectFrameDragHorz = 
		CRect(rect.TopLeft(), pSzBar->m_FloatSize);
   	
   	// To work out the size we actually create a floating mini frame, and then see how big
   	// it is
	CMiniDockFrameWnd* pFloatFrame =
		m_pDockSite->CreateFloatingFrame(bHorz ? CBRS_ALIGN_TOP : CBRS_ALIGN_LEFT);
   	if (pFloatFrame == NULL)
		AfxThrowMemoryException();
   	pFloatFrame->CalcWindowRect(&m_rectFrameDragHorz);
   	pFloatFrame->CalcWindowRect(&m_rectFrameDragVert);
// 	m_rectFrameDragHorz.InflateRect(-afxData.cxBorder2, -afxData.cyBorder2);
// 	m_rectFrameDragVert.InflateRect(-afxData.cxBorder2, -afxData.cyBorder2);
   	pFloatFrame->DestroyWindow();

	// adjust rectangles so that point is inside
	AdjustRectangle(m_rectDragHorzAlone, pt);
	AdjustRectangle(m_rectDragVertAlone, pt);
   	AdjustRectangle(m_rectDragHorz, pt);
   	AdjustRectangle(m_rectDragVert, pt);
   	AdjustRectangle(m_rectFrameDragHorz, pt);
   	AdjustRectangle(m_rectFrameDragVert, pt);
	
   	// lock window update while dragging
   	ASSERT(m_pDC == NULL);
   	CWnd* pWnd = CWnd::GetDesktopWindow();
#ifndef _MAC
    if (pWnd->LockWindowUpdate()) 
		m_pDC = pWnd->GetDCEx(NULL, DCX_WINDOW|DCX_CACHE|DCX_LOCKWINDOWUPDATE);
    else
#endif
		m_pDC = pWnd->GetDCEx(NULL, DCX_WINDOW|DCX_CACHE);
    ASSERT(m_pDC != NULL); 
	
	// initialize tracking state and enter tracking loop
	m_dwOverDockStyle = CanDock();
    Move(pt);   // call it here to handle special keys
    Track();
}
Пример #5
0
mozilla::ipc::IPCResult
DocAccessibleParent::RecvShowEvent(const ShowEventData& aData,
                                   const bool& aFromUser)
{
  if (mShutdown)
    return IPC_OK();

  MOZ_ASSERT(CheckDocTree());

  if (aData.NewTree().IsEmpty()) {
    return IPC_FAIL(this, "No children being added");
  }

  ProxyAccessible* parent = GetAccessible(aData.ID());

  // XXX This should really never happen, but sometimes we fail to fire the
  // required show events.
  if (!parent) {
    NS_ERROR("adding child to unknown accessible");
#ifdef DEBUG
    return IPC_FAIL(this, "unknown parent accessible");
#else
    return IPC_OK();
#endif
  }

  uint32_t newChildIdx = aData.Idx();
  if (newChildIdx > parent->ChildrenCount()) {
    NS_ERROR("invalid index to add child at");
#ifdef DEBUG
    return IPC_FAIL(this, "invalid index");
#else
    return IPC_OK();
#endif
  }

  uint32_t consumed = AddSubtree(parent, aData.NewTree(), 0, newChildIdx);
  MOZ_ASSERT(consumed == aData.NewTree().Length());

  // XXX This shouldn't happen, but if we failed to add children then the below
  // is pointless and can crash.
  if (!consumed) {
    return IPC_FAIL(this, "failed to add children");
  }

#ifdef DEBUG
  for (uint32_t i = 0; i < consumed; i++) {
    uint64_t id = aData.NewTree()[i].ID();
    MOZ_ASSERT(mAccessibles.GetEntry(id));
  }
#endif

  MOZ_ASSERT(CheckDocTree());

  ProxyAccessible* target = parent->ChildAt(newChildIdx);
  ProxyShowHideEvent(target, parent, true, aFromUser);

  if (!nsCoreUtils::AccEventObserversExist()) {
    return IPC_OK();
  }

  uint32_t type = nsIAccessibleEvent::EVENT_SHOW;
  xpcAccessibleGeneric* xpcAcc = GetXPCAccessible(target);
  xpcAccessibleDocument* doc = GetAccService()->GetXPCDocument(this);
  nsIDOMNode* node = nullptr;
  RefPtr<xpcAccEvent> event = new xpcAccEvent(type, xpcAcc, doc, node,
                                              aFromUser);
  nsCoreUtils::DispatchAccEvent(Move(event));

  return IPC_OK();
}
Пример #6
0
void
AudioCallbackAdapter::Decoded(const nsTArray<int16_t>& aPCM, uint64_t aTimeStamp, uint32_t aChannels, uint32_t aRate)
{
  MOZ_ASSERT(IsOnGMPThread());

  if (aRate == 0 || aChannels == 0) {
    NS_WARNING("Invalid rate or num channels returned on GMP audio samples");
    mCallback->Error();
    return;
  }

  size_t numFrames = aPCM.Length() / aChannels;
  MOZ_ASSERT((aPCM.Length() % aChannels) == 0);
  AlignedAudioBuffer audioData(aPCM.Length());
  if (!audioData) {
    mCallback->Error();
    return;
  }

  for (size_t i = 0; i < aPCM.Length(); ++i) {
    audioData[i] = AudioSampleToFloat(aPCM[i]);
  }

  if (mMustRecaptureAudioPosition) {
    mAudioFrameSum = 0;
    auto timestamp = UsecsToFrames(aTimeStamp, aRate);
    if (!timestamp.isValid()) {
      NS_WARNING("Invalid timestamp");
      mCallback->Error();
      return;
    }
    mAudioFrameOffset = timestamp.value();
    mMustRecaptureAudioPosition = false;
  }

  auto timestamp = FramesToUsecs(mAudioFrameOffset + mAudioFrameSum, aRate);
  if (!timestamp.isValid()) {
    NS_WARNING("Invalid timestamp on audio samples");
    mCallback->Error();
    return;
  }
  mAudioFrameSum += numFrames;

  auto duration = FramesToUsecs(numFrames, aRate);
  if (!duration.isValid()) {
    NS_WARNING("Invalid duration on audio samples");
    mCallback->Error();
    return;
  }

  RefPtr<AudioData> audio(new AudioData(mLastStreamOffset,
                                        timestamp.value(),
                                        duration.value(),
                                        numFrames,
                                        Move(audioData),
                                        aChannels,
                                        aRate));

#ifdef LOG_SAMPLE_DECODE
  LOG("Decoded audio sample! timestamp=%lld duration=%lld currentLength=%u",
      timestamp, duration, currentLength);
#endif

  mCallback->Output(audio);
}
Пример #7
0
nsresult
SourceBuffer::Append(const char* aData, size_t aLength)
{
  MOZ_ASSERT(aData, "Should have a buffer");
  MOZ_ASSERT(aLength > 0, "Writing a zero-sized chunk");

  size_t currentChunkCapacity = 0;
  size_t currentChunkLength = 0;
  char* currentChunkData = nullptr;
  size_t currentChunkRemaining = 0;
  size_t forCurrentChunk = 0;
  size_t forNextChunk = 0;
  size_t nextChunkCapacity = 0;

  {
    MutexAutoLock lock(mMutex);

    if (MOZ_UNLIKELY(mStatus)) {
      // This SourceBuffer is already complete; ignore further data.
      return NS_ERROR_FAILURE;
    }

    if (MOZ_UNLIKELY(mChunks.Length() == 0)) {
      if (MOZ_UNLIKELY(NS_FAILED(AppendChunk(CreateChunk(aLength))))) {
        return HandleError(NS_ERROR_OUT_OF_MEMORY);
      }
    }

    // Copy out the current chunk's information so we can release the lock.
    // Note that this wouldn't be safe if multiple producers were allowed!
    Chunk& currentChunk = mChunks.LastElement();
    currentChunkCapacity = currentChunk.Capacity();
    currentChunkLength = currentChunk.Length();
    currentChunkData = currentChunk.Data();

    // Partition this data between the current chunk and the next chunk.
    // (Because we always allocate a chunk big enough to fit everything passed
    // to Append, we'll never need more than those two chunks to store
    // everything.)
    currentChunkRemaining = currentChunkCapacity - currentChunkLength;
    forCurrentChunk = min(aLength, currentChunkRemaining);
    forNextChunk = aLength - forCurrentChunk;

    // If we'll need another chunk, determine what its capacity should be while
    // we still hold the lock.
    nextChunkCapacity = forNextChunk > 0
                      ? FibonacciCapacityWithMinimum(forNextChunk)
                      : 0;
  }

  // Write everything we can fit into the current chunk.
  MOZ_ASSERT(currentChunkLength + forCurrentChunk <= currentChunkCapacity);
  memcpy(currentChunkData + currentChunkLength, aData, forCurrentChunk);

  // If there's something left, create a new chunk and write it there.
  Maybe<Chunk> nextChunk;
  if (forNextChunk > 0) {
    MOZ_ASSERT(nextChunkCapacity >= forNextChunk, "Next chunk too small?");
    nextChunk = CreateChunk(nextChunkCapacity);
    if (MOZ_LIKELY(nextChunk && !nextChunk->AllocationFailed())) {
      memcpy(nextChunk->Data(), aData + forCurrentChunk, forNextChunk);
      nextChunk->AddLength(forNextChunk);
    }
  }

  // Update shared data structures.
  {
    MutexAutoLock lock(mMutex);

    // Update the length of the current chunk.
    Chunk& currentChunk = mChunks.LastElement();
    MOZ_ASSERT(currentChunk.Data() == currentChunkData, "Multiple producers?");
    MOZ_ASSERT(currentChunk.Length() == currentChunkLength,
               "Multiple producers?");

    currentChunk.AddLength(forCurrentChunk);

    // If we created a new chunk, add it to the series.
    if (forNextChunk > 0) {
      if (MOZ_UNLIKELY(!nextChunk)) {
        return HandleError(NS_ERROR_OUT_OF_MEMORY);
      }

      if (MOZ_UNLIKELY(NS_FAILED(AppendChunk(Move(nextChunk))))) {
        return HandleError(NS_ERROR_OUT_OF_MEMORY);
      }
    }

    // Resume any waiting readers now that there's new data.
    ResumeWaitingConsumers();
  }

  return NS_OK;
}
Пример #8
0
STATIC I32
S_do_trans_complex(pTHX_ SV * const sv)
{
    STRLEN len;
    U8 *s = (U8*)SvPV_nomg(sv, len);
    U8 * const send = s+len;
    I32 matches = 0;
    const short * const tbl = (short*)cPVOP->op_pv;

    PERL_ARGS_ASSERT_DO_TRANS_COMPLEX;

    if (!tbl)
        Perl_croak(aTHX_ "panic: do_trans_complex line %d",__LINE__);

    if (!SvUTF8(sv)) {
        U8 *d = s;
        U8 * const dstart = d;

        if (PL_op->op_private & OPpTRANS_SQUASH) {
            const U8* p = send;
            while (s < send) {
                const I32 ch = tbl[*s];
                if (ch >= 0) {
                    *d = (U8)ch;
                    matches++;
                    if (p != d - 1 || *p != *d)
                        p = d++;
                }
                else if (ch == -1)	/* -1 is unmapped character */
                    *d++ = *s;	
                else if (ch == -2)	/* -2 is delete character */
                    matches++;
                s++;
            }
        }
        else {
            while (s < send) {
                const I32 ch = tbl[*s];
                if (ch >= 0) {
                    matches++;
                    *d++ = (U8)ch;
                }
                else if (ch == -1)	/* -1 is unmapped character */
                    *d++ = *s;
                else if (ch == -2)      /* -2 is delete character */
                    matches++;
                s++;
            }
        }
        *d = '\0';
        SvCUR_set(sv, d - dstart);
    }
    else { /* is utf8 */
        const I32 complement = PL_op->op_private & OPpTRANS_COMPLEMENT;
        const I32 grows = PL_op->op_private & OPpTRANS_GROWS;
        const I32 del = PL_op->op_private & OPpTRANS_DELETE;
        U8 *d;
        U8 *dstart;
        STRLEN rlen = 0;

        if (grows)
            Newx(d, len*2+1, U8);
        else
            d = s;
        dstart = d;
        if (complement && !del)
            rlen = tbl[0x100];

        if (PL_op->op_private & OPpTRANS_SQUASH) {
            UV pch = 0xfeedface;
            while (s < send) {
                STRLEN len;
                const UV comp = utf8n_to_uvchr(s, send - s, &len,
                                               UTF8_ALLOW_DEFAULT);
                I32 ch;

                if (comp > 0xff) {
                    if (!complement) {
                        Move(s, d, len, U8);
                        d += len;
                    }
                    else {
                        matches++;
                        if (!del) {
                            ch = (rlen == 0) ? (I32)comp :
                                (comp - 0x100 < rlen) ?
                                tbl[comp+1] : tbl[0x100+rlen];
                            if ((UV)ch != pch) {
                                d = uvchr_to_utf8(d, ch);
                                pch = (UV)ch;
                            }
                            s += len;
                            continue;
                        }
                    }
                }
                else if ((ch = tbl[comp]) >= 0) {
                    matches++;
                    if ((UV)ch != pch) {
                        d = uvchr_to_utf8(d, ch);
                        pch = (UV)ch;
                    }
                    s += len;
                    continue;
                }
                else if (ch == -1) {	/* -1 is unmapped character */
                    Move(s, d, len, U8);
                    d += len;
                }
                else if (ch == -2)      /* -2 is delete character */
                    matches++;
                s += len;
                pch = 0xfeedface;
            }
        }
        else {
            while (s < send) {
                STRLEN len;
                const UV comp = utf8n_to_uvchr(s, send - s, &len,
                                               UTF8_ALLOW_DEFAULT);
                I32 ch;
                if (comp > 0xff) {
                    if (!complement) {
                        Move(s, d, len, U8);
                        d += len;
                    }
                    else {
                        matches++;
                        if (!del) {
                            if (comp - 0x100 < rlen)
                                d = uvchr_to_utf8(d, tbl[comp+1]);
                            else
                                d = uvchr_to_utf8(d, tbl[0x100+rlen]);
                        }
                    }
                }
                else if ((ch = tbl[comp]) >= 0) {
                    d = uvchr_to_utf8(d, ch);
                    matches++;
                }
                else if (ch == -1) {	/* -1 is unmapped character */
                    Move(s, d, len, U8);
                    d += len;
                }
                else if (ch == -2)      /* -2 is delete character */
                    matches++;
                s += len;
            }
        }
        if (grows) {
            sv_setpvn(sv, (char*)dstart, d - dstart);
            Safefree(dstart);
        }
        else {
            *d = '\0';
            SvCUR_set(sv, d - dstart);
        }
        SvUTF8_on(sv);
    }
    SvSETMAGIC(sv);
    return matches;
}
Пример #9
0
STATIC I32
S_do_trans_simple(pTHX_ SV * const sv)
{
    I32 matches = 0;
    STRLEN len;
    U8 *s = (U8*)SvPV_nomg(sv,len);
    U8 * const send = s+len;
    const short * const tbl = (short*)cPVOP->op_pv;

    PERL_ARGS_ASSERT_DO_TRANS_SIMPLE;

    if (!tbl)
        Perl_croak(aTHX_ "panic: do_trans_simple line %d",__LINE__);

    /* First, take care of non-UTF-8 input strings, because they're easy */
    if (!SvUTF8(sv)) {
        while (s < send) {
            const I32 ch = tbl[*s];
            if (ch >= 0) {
                matches++;
                *s = (U8)ch;
            }
            s++;
        }
        SvSETMAGIC(sv);
    }
    else {
        const I32 grows = PL_op->op_private & OPpTRANS_GROWS;
        U8 *d;
        U8 *dstart;

        /* Allow for expansion: $_="a".chr(400); tr/a/\xFE/, FE needs encoding */
        if (grows)
            Newx(d, len*2+1, U8);
        else
            d = s;
        dstart = d;
        while (s < send) {
            STRLEN ulen;
            I32 ch;

            /* Need to check this, otherwise 128..255 won't match */
            const UV c = utf8n_to_uvchr(s, send - s, &ulen, UTF8_ALLOW_DEFAULT);
            if (c < 0x100 && (ch = tbl[c]) >= 0) {
                matches++;
                d = uvchr_to_utf8(d, ch);
                s += ulen;
            }
            else { /* No match -> copy */
                Move(s, d, ulen, U8);
                d += ulen;
                s += ulen;
            }
        }
        if (grows) {
            sv_setpvn(sv, (char*)dstart, d - dstart);
            Safefree(dstart);
        }
        else {
            *d = '\0';
            SvCUR_set(sv, d - dstart);
        }
        SvUTF8_on(sv);
        SvSETMAGIC(sv);
    }
    return matches;
}
Пример #10
0
void Character::Update(double dt)
{
	attackBuffer -= dt;

	switch (role)
	{
	case ROLE::KNIGHT:
		switch (state)
		{
		case STATE::KNIGHT_IDLE:
			break;
		case STATE::KNIGHT_MOVE:
		case STATE::KNIGHT_PROTECT:
			if (target != NULL)
			Move(target->getPos() - getPos(), dt);
			break;
		case STATE::KNIGHT_ATTACK:
			if (attackBuffer < 0)
			{
				if (target != NULL)
					target->hp -= 10;
				attackBuffer = 0.5f;
			}
			break;
		}
		break;
	case ROLE::ARCHER:
		switch (state)
		{
		case STATE::ARCHER_IDLE:
			break;
		case STATE::ARCHER_MOVE:
			Move(target->getPos() - getPos(), dt);
			break;
		case STATE::ARCHER_ATTACK:
			if (attackBuffer < 0)
			{
				if (target != NULL)
					target->hp -= 10;
				attackBuffer = 0.5f;
			}
			break;
		case STATE::ARCHER_RETREAT:
			Move(getPos() - attacker->getPos(), dt);
			break;
		}
		break;
	case ROLE::HEALER:
		switch (state)
		{
		case STATE::HEALER_MOVE:
			Move(target->getPos() - getPos(), dt);
			break;
		case STATE::HEALER_HEAL:
			if (target != NULL)
			if (attackBuffer < 0 && target->hp <= target->getMaxHP())
			{
				target->hp += 10;
				attackBuffer = 2.f;
			}
			break;
		case STATE::HEALER_RETREAT:
			Move(getPos() - attacker->getPos(), dt);
			break;
		}
		break;
	case ROLE::MONSTER:
		switch (state)
		{
		case STATE::MONSTER_PATROL:
		case STATE::MONSTER_MOVE:
			Move(target->getPos() - getPos(), dt);
			break;
		case STATE::MONSTER_ATTACK:
			if (attackBuffer < 0)
			{
				if (target != NULL)
					target->hp -= 10;
				attackBuffer = 0.5f;
			}
			target->attacked = true;
			target->attacker = this;
			break;
		}
	default:
		break;
	}
}
Пример #11
0
 void Move(const PixelRect rc) {
   Move(rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top);
 }
Пример #12
0
void
LayerManagerComposite::Render(const nsIntRegion& aInvalidRegion)
{
  PROFILER_LABEL("LayerManagerComposite", "Render",
    js::ProfileEntry::Category::GRAPHICS);

  if (mDestroyed) {
    NS_WARNING("Call on destroyed layer manager");
    return;
  }

  // At this time, it doesn't really matter if these preferences change
  // during the execution of the function; we should be safe in all
  // permutations. However, may as well just get the values onces and
  // then use them, just in case the consistency becomes important in
  // the future.
  bool invertVal = gfxPrefs::LayersEffectInvert();
  bool grayscaleVal = gfxPrefs::LayersEffectGrayscale();
  float contrastVal = gfxPrefs::LayersEffectContrast();
  bool haveLayerEffects = (invertVal || grayscaleVal || contrastVal != 0.0);

  // Set LayerScope begin/end frame
  LayerScopeAutoFrame frame(PR_Now());

  // Dump to console
  if (gfxPrefs::LayersDump()) {
    this->Dump();
  } else if (profiler_feature_active("layersdump")) {
    std::stringstream ss;
    Dump(ss);
    profiler_log(ss.str().c_str());
  }

  // Dump to LayerScope Viewer
  if (LayerScope::CheckSendable()) {
    // Create a LayersPacket, dump Layers into it and transfer the
    // packet('s ownership) to LayerScope.
    auto packet = MakeUnique<layerscope::Packet>();
    layerscope::LayersPacket* layersPacket = packet->mutable_layers();
    this->Dump(layersPacket);
    LayerScope::SendLayerDump(Move(packet));
  }

  /** Our more efficient but less powerful alter ego, if one is available. */
  RefPtr<Composer2D> composer2D;
  composer2D = mCompositor->GetWidget()->GetComposer2D();

  // We can't use composert2D if we have layer effects
  if (!mTarget && !haveLayerEffects &&
      gfxPrefs::Composer2DCompositionEnabled() &&
      composer2D && composer2D->HasHwc() && composer2D->TryRenderWithHwc(mRoot,
          mCompositor->GetWidget(), mGeometryChanged))
  {
    LayerScope::SetHWComposed();
    if (mFPS) {
      double fps = mFPS->mCompositionFps.AddFrameAndGetFps(TimeStamp::Now());
      if (gfxPrefs::LayersDrawFPS()) {
        printf_stderr("HWComposer: FPS is %g\n", fps);
      }
    }
    mCompositor->EndFrameForExternalComposition(Matrix());
    mLastFrameMissedHWC = false;
    return;
  } else if (!mTarget && !haveLayerEffects) {
    mLastFrameMissedHWC = !!composer2D;
  }

  {
    PROFILER_LABEL("LayerManagerComposite", "PreRender",
      js::ProfileEntry::Category::GRAPHICS);

    if (!mCompositor->GetWidget()->PreRender(this)) {
      return;
    }
  }

  ParentLayerIntRect clipRect;
  Rect bounds(mRenderBounds.x, mRenderBounds.y, mRenderBounds.width, mRenderBounds.height);
  Rect actualBounds;

  CompositorBench(mCompositor, bounds);

  if (mRoot->GetClipRect()) {
    clipRect = *mRoot->GetClipRect();
    Rect rect(clipRect.x, clipRect.y, clipRect.width, clipRect.height);
    mCompositor->BeginFrame(aInvalidRegion, &rect, bounds, nullptr, &actualBounds);
  } else {
    gfx::Rect rect;
    mCompositor->BeginFrame(aInvalidRegion, nullptr, bounds, &rect, &actualBounds);
    clipRect = ParentLayerIntRect(rect.x, rect.y, rect.width, rect.height);
  }

  if (actualBounds.IsEmpty()) {
    mCompositor->GetWidget()->PostRender(this);
    return;
  }

  // Allow widget to render a custom background.
  mCompositor->GetWidget()->DrawWindowUnderlay(this, IntRect(actualBounds.x,
                                                               actualBounds.y,
                                                               actualBounds.width,
                                                               actualBounds.height));

  RefPtr<CompositingRenderTarget> previousTarget;
  if (haveLayerEffects) {
    previousTarget = PushGroupForLayerEffects();
  } else {
    mTwoPassTmpTarget = nullptr;
  }

  // Render our layers.
  RootLayer()->Prepare(ViewAs<RenderTargetPixel>(clipRect, PixelCastJustification::RenderTargetIsParentLayerForRoot));
  RootLayer()->RenderLayer(clipRect.ToUnknownRect());

  if (!mRegionToClear.IsEmpty()) {
    nsIntRegionRectIterator iter(mRegionToClear);
    const IntRect *r;
    while ((r = iter.Next())) {
      mCompositor->ClearRect(Rect(r->x, r->y, r->width, r->height));
    }
  }

  if (mTwoPassTmpTarget) {
    MOZ_ASSERT(haveLayerEffects);
    PopGroupForLayerEffects(previousTarget, clipRect.ToUnknownRect(),
                            grayscaleVal, invertVal, contrastVal);
  }

  // Allow widget to render a custom foreground.
  mCompositor->GetWidget()->DrawWindowOverlay(
    this, LayoutDeviceIntRect(actualBounds.x, actualBounds.y,
                              actualBounds.width, actualBounds.height));

  // Debugging
  RenderDebugOverlay(actualBounds);

  {
    PROFILER_LABEL("LayerManagerComposite", "EndFrame",
      js::ProfileEntry::Category::GRAPHICS);

    mCompositor->EndFrame();
    mCompositor->SetDispAcquireFence(mRoot,
                                     mCompositor->GetWidget()); // Call after EndFrame()
  }

  if (composer2D) {
    composer2D->Render(mCompositor->GetWidget());
  }

  mCompositor->GetWidget()->PostRender(this);

  RecordFrame();
}
Пример #13
0
void
LayerManagerComposite::UpdateAndRender()
{
  nsIntRegion invalid;
  bool didEffectiveTransforms = false;

  if (mClonedLayerTreeProperties) {
    // Effective transforms are needed by ComputeDifferences().
    mRoot->ComputeEffectiveTransforms(gfx::Matrix4x4());
    didEffectiveTransforms = true;

    // We need to compute layer tree differences even if we're not going to
    // immediately use the resulting damage area, since ComputeDifferences
    // is also responsible for invalidates intermediate surfaces in
    // ContainerLayers.
    nsIntRegion changed = mClonedLayerTreeProperties->ComputeDifferences(mRoot, nullptr, &mGeometryChanged);

    if (mTarget) {
      // Since we're composing to an external target, we're not going to use
      // the damage region from layers changes - we want to composite
      // everything in the target bounds. Instead we accumulate the layers
      // damage region for the next window composite.
      mInvalidRegion.Or(mInvalidRegion, changed);
    } else {
      invalid = Move(changed);
    }
  }

  if (mTarget) {
    invalid.Or(invalid, mTargetBounds);
  } else {
    // If we didn't have a previous layer tree, invalidate the entire render
    // area.
    if (!mClonedLayerTreeProperties) {
      invalid.Or(invalid, mRenderBounds);
    }

    // Add any additional invalid rects from the window manager or previous
    // damage computed during ComposeToTarget().
    invalid.Or(invalid, mInvalidRegion);
    mInvalidRegion.SetEmpty();
  }

  // Update cached layer tree information.
  mClonedLayerTreeProperties = LayerProperties::CloneFrom(GetRoot());

  if (invalid.IsEmpty() && !mWindowOverlayChanged) {
    // Composition requested, but nothing has changed. Don't do any work.
    return;
  }

  // We don't want our debug overlay to cause more frames to happen
  // so we will invalidate after we've decided if something changed.
  InvalidateDebugOverlay(mRenderBounds);

  if (!didEffectiveTransforms) {
    // The results of our drawing always go directly into a pixel buffer,
    // so we don't need to pass any global transform here.
    mRoot->ComputeEffectiveTransforms(gfx::Matrix4x4());
  }

  nsIntRegion opaque;
  LayerIntRegion visible;
  PostProcessLayers(mRoot, opaque, visible);

  Render(invalid);
#if defined(MOZ_WIDGET_ANDROID) || defined(MOZ_WIDGET_GONK)
  RenderToPresentationSurface();
#endif
  mGeometryChanged = false;
  mWindowOverlayChanged = false;
}
Пример #14
0
DrawableSurface
RasterImage::LookupFrame(const IntSize& aSize,
                         uint32_t aFlags,
                         PlaybackType aPlaybackType)
{
  MOZ_ASSERT(NS_IsMainThread());

  // If we're opaque, we don't need to care about premultiplied alpha, because
  // that can only matter for frames with transparency.
  if (IsOpaque()) {
    aFlags &= ~FLAG_DECODE_NO_PREMULTIPLY_ALPHA;
  }

  IntSize requestedSize = CanDownscaleDuringDecode(aSize, aFlags)
                        ? aSize : mSize;
  if (requestedSize.IsEmpty()) {
    return DrawableSurface();  // Can't decode to a surface of zero size.
  }

  LookupResult result =
    LookupFrameInternal(requestedSize, aFlags, aPlaybackType);

  if (!result && !mHasSize) {
    // We can't request a decode without knowing our intrinsic size. Give up.
    return DrawableSurface();
  }

  if (result.Type() == MatchType::NOT_FOUND ||
      result.Type() == MatchType::SUBSTITUTE_BECAUSE_NOT_FOUND ||
      ((aFlags & FLAG_SYNC_DECODE) && !result)) {
    // We don't have a copy of this frame, and there's no decoder working on
    // one. (Or we're sync decoding and the existing decoder hasn't even started
    // yet.) Trigger decoding so it'll be available next time.
    MOZ_ASSERT(aPlaybackType != PlaybackType::eAnimated ||
               !mAnimationState || mAnimationState->KnownFrameCount() < 1,
               "Animated frames should be locked");

    bool ranSync = Decode(requestedSize, aFlags, aPlaybackType);

    // If we can or did sync decode, we should already have the frame.
    if (ranSync || (aFlags & FLAG_SYNC_DECODE)) {
      result = LookupFrameInternal(requestedSize, aFlags, aPlaybackType);
    }
  }

  if (!result) {
    // We still weren't able to get a frame. Give up.
    return DrawableSurface();
  }

  if (result.Surface()->GetCompositingFailed()) {
    return DrawableSurface();
  }

  MOZ_ASSERT(!result.Surface()->GetIsPaletted(),
             "Should not have a paletted frame");

  // Sync decoding guarantees that we got the frame, but if it's owned by an
  // async decoder that's currently running, the contents of the frame may not
  // be available yet. Make sure we get everything.
  if (mHasSourceData && (aFlags & FLAG_SYNC_DECODE)) {
    result.Surface()->WaitUntilFinished();
  }

  // If we could have done some decoding in this function we need to check if
  // that decoding encountered an error and hence aborted the surface. We want
  // to avoid calling IsAborted if we weren't passed any sync decode flag because
  // IsAborted acquires the monitor for the imgFrame.
  if (aFlags & (FLAG_SYNC_DECODE | FLAG_SYNC_DECODE_IF_FAST) &&
    result.Surface()->IsAborted()) {
    return DrawableSurface();
  }

  return Move(result.Surface());
}
Пример #15
0
RefPtr<DtlsIdentity> DtlsIdentity::Generate() {
    UniquePK11SlotInfo slot(PK11_GetInternalSlot());
    if (!slot) {
        return nullptr;
    }

    uint8_t random_name[16];

    SECStatus rv = PK11_GenerateRandomOnSlot(slot.get(), random_name,
                   sizeof(random_name));
    if (rv != SECSuccess)
        return nullptr;

    std::string name;
    char chunk[3];
    for (size_t i = 0; i < sizeof(random_name); ++i) {
        SprintfLiteral(chunk, "%.2x", random_name[i]);
        name += chunk;
    }

    std::string subject_name_string = "CN=" + name;
    UniqueCERTName subject_name(CERT_AsciiToName(subject_name_string.c_str()));
    if (!subject_name) {
        return nullptr;
    }

    unsigned char paramBuf[12]; // OIDs are small
    SECItem ecdsaParams = { siBuffer, paramBuf, sizeof(paramBuf) };
    SECOidData* oidData = SECOID_FindOIDByTag(SEC_OID_SECG_EC_SECP256R1);
    if (!oidData || (oidData->oid.len > (sizeof(paramBuf) - 2))) {
        return nullptr;
    }
    ecdsaParams.data[0] = SEC_ASN1_OBJECT_ID;
    ecdsaParams.data[1] = oidData->oid.len;
    memcpy(ecdsaParams.data + 2, oidData->oid.data, oidData->oid.len);
    ecdsaParams.len = oidData->oid.len + 2;

    SECKEYPublicKey *pubkey;
    UniqueSECKEYPrivateKey private_key(
        PK11_GenerateKeyPair(slot.get(),
                             CKM_EC_KEY_PAIR_GEN, &ecdsaParams, &pubkey,
                             PR_FALSE, PR_TRUE, nullptr));
    if (private_key == nullptr)
        return nullptr;
    UniqueSECKEYPublicKey public_key(pubkey);
    pubkey = nullptr;

    UniqueCERTSubjectPublicKeyInfo spki(
        SECKEY_CreateSubjectPublicKeyInfo(public_key.get()));
    if (!spki) {
        return nullptr;
    }

    UniqueCERTCertificateRequest certreq(
        CERT_CreateCertificateRequest(subject_name.get(), spki.get(), nullptr));
    if (!certreq) {
        return nullptr;
    }

    // From 1 day before todayto 30 days after.
    // This is a sort of arbitrary range designed to be valid
    // now with some slack in case the other side expects
    // some before expiry.
    //
    // Note: explicit casts necessary to avoid
    //       warning C4307: '*' : integral constant overflow
    static const PRTime oneDay = PRTime(PR_USEC_PER_SEC)
                                 * PRTime(60)  // sec
                                 * PRTime(60)  // min
                                 * PRTime(24); // hours
    PRTime now = PR_Now();
    PRTime notBefore = now - oneDay;
    PRTime notAfter = now + (PRTime(30) * oneDay);

    UniqueCERTValidity validity(CERT_CreateValidity(notBefore, notAfter));
    if (!validity) {
        return nullptr;
    }

    unsigned long serial;
    // Note: This serial in principle could collide, but it's unlikely
    rv = PK11_GenerateRandomOnSlot(slot.get(),
                                   reinterpret_cast<unsigned char *>(&serial),
                                   sizeof(serial));
    if (rv != SECSuccess) {
        return nullptr;
    }

    UniqueCERTCertificate certificate(
        CERT_CreateCertificate(serial, subject_name.get(), validity.get(),
                               certreq.get()));
    if (!certificate) {
        return nullptr;
    }

    PLArenaPool *arena = certificate->arena;

    rv = SECOID_SetAlgorithmID(arena, &certificate->signature,
                               SEC_OID_ANSIX962_ECDSA_SHA256_SIGNATURE, 0);
    if (rv != SECSuccess)
        return nullptr;

    // Set version to X509v3.
    *(certificate->version.data) = SEC_CERTIFICATE_VERSION_3;
    certificate->version.len = 1;

    SECItem innerDER;
    innerDER.len = 0;
    innerDER.data = nullptr;

    if (!SEC_ASN1EncodeItem(arena, &innerDER, certificate.get(),
                            SEC_ASN1_GET(CERT_CertificateTemplate))) {
        return nullptr;
    }

    SECItem *signedCert = PORT_ArenaZNew(arena, SECItem);
    if (!signedCert) {
        return nullptr;
    }

    rv = SEC_DerSignData(arena, signedCert, innerDER.data, innerDER.len,
                         private_key.get(),
                         SEC_OID_ANSIX962_ECDSA_SHA256_SIGNATURE);
    if (rv != SECSuccess) {
        return nullptr;
    }
    certificate->derCert = *signedCert;

    RefPtr<DtlsIdentity> identity = new DtlsIdentity(Move(private_key),
            Move(certificate),
            ssl_kea_ecdh);
    return identity.forget();
}
Пример #16
0
STATIC I32
S_do_trans_simple_utf8(pTHX_ SV * const sv)
{
    U8 *s;
    U8 *send;
    U8 *d;
    U8 *start;
    U8 *dstart, *dend;
    I32 matches = 0;
    const I32 grows = PL_op->op_private & OPpTRANS_GROWS;
    STRLEN len;
    SV* const  rv =
#ifdef USE_ITHREADS
                    PAD_SVl(cPADOP->op_padix);
#else
                    MUTABLE_SV(cSVOP->op_sv);
#endif
    HV* const  hv = MUTABLE_HV(SvRV(rv));
    SV* const * svp = hv_fetchs(hv, "NONE", FALSE);
    const UV none = svp ? SvUV(*svp) : 0x7fffffff;
    const UV extra = none + 1;
    UV final = 0;
    U8 hibit = 0;

    PERL_ARGS_ASSERT_DO_TRANS_SIMPLE_UTF8;

    s = (U8*)SvPV_nomg(sv, len);
    if (!SvUTF8(sv)) {
        const U8 *t = s;
        const U8 * const e = s + len;
        while (t < e) {
            const U8 ch = *t++;
            hibit = !NATIVE_BYTE_IS_INVARIANT(ch);
            if (hibit) {
                s = bytes_to_utf8(s, &len);
                break;
            }
        }
    }
    send = s + len;
    start = s;

    svp = hv_fetchs(hv, "FINAL", FALSE);
    if (svp)
        final = SvUV(*svp);

    if (grows) {
        /* d needs to be bigger than s, in case e.g. upgrading is required */
        Newx(d, len * 3 + UTF8_MAXBYTES, U8);
        dend = d + len * 3;
        dstart = d;
    }
    else {
        dstart = d = s;
        dend = d + len;
    }

    while (s < send) {
        const UV uv = swash_fetch(rv, s, TRUE);
        if (uv < none) {
            s += UTF8SKIP(s);
            matches++;
            d = uvchr_to_utf8(d, uv);
        }
        else if (uv == none) {
            const int i = UTF8SKIP(s);
            Move(s, d, i, U8);
            d += i;
            s += i;
        }
        else if (uv == extra) {
            s += UTF8SKIP(s);
            matches++;
            d = uvchr_to_utf8(d, final);
        }
        else
Пример #17
0
task main()
{

	initializeRobot();

	waitForStart(); // Wait for the beginning of autonomous phase.
	StartTask( Zelda_Theme );
int DistFrom = 30; // in Cm
int Deadband = 2;
int Distmin = 35;
// In Inches
float COUNTS_PER_INCH = 90.55;

nMotorEncoder[R_Motor] = 0;
nMotorEncoder[L_Motor] = 0;
servo[IRS_1] = 160;
servo[Block_Chuck] = 000;
ClearTimer(T1);
while (SensorValue[IR] != 6 && nMotorEncoder[ L_Motor] / COUNTS_PER_INCH < Distmin && nMotorEncoder[L_Motor] / COUNTS_PER_INCH < Distmin && time100[T1] < 50 )
{

	if ((USreadDist(SONAR_1) < DistFrom - Deadband) && (nMotorEncoder[ L_Motor] / COUNTS_PER_INCH > 18))
	{
		motor[L_Motor] = 25;
		motor[R_Motor] = 50;
  }
  else if ((USreadDist(SONAR_1) > DistFrom + Deadband) && (nMotorEncoder[ L_Motor] / COUNTS_PER_INCH > 18))
  {
  	motor[L_Motor] = 50;
  	motor[R_Motor] = 25;

  }
  else
  {
  	motor[L_Motor] = 50;
		motor[R_Motor] = 50;
	}

}//End of while.
	motor[L_Motor] = 0;
	motor[R_Motor] = 0;
	wait10Msec(55);

	servo[Block_Chuck] = 255;
	wait10Msec(55);

	servo[Block_Chuck] = 0;
	wait10Msec(55);
while( USreadDist(SONAR_1) < 60)
{
	if ((USreadDist(SONAR_1) < DistFrom - Deadband) && (nMotorEncoder[ L_Motor] / COUNTS_PER_INCH > 18))
	{
		motor[L_Motor] = 25;
		motor[R_Motor] = 50;
  }
  else if ((USreadDist(SONAR_1) > DistFrom + Deadband) && (nMotorEncoder[ L_Motor] / COUNTS_PER_INCH > 18))
  {
  	motor[L_Motor] = 50;
  	motor[R_Motor] = 25;

  }
  else
  {
  	motor[L_Motor] = 50;
		motor[R_Motor] = 50;

	}

	/*	if (time100[T1] > 60 || nMotorEncoder[L_Motor] / COUNTS_PER_INCH > 40)

	{
		motor[L_Motor] = 0;
		motor[R_Motor] = 0;
		noOp();
		alive();
		StopAllTasks();
		wait10Msec(55);
	}*/
}//End of while
	  motor[L_Motor] = 0;
		motor[R_Motor] = 0;
		wait10Msec(55);

		Turn(65);
		wait10Msec(55);

		Move(25,100);
		wait10Msec(55);

		Turn(75);
		wait10Msec(55);

		Move(30 ,100);
		wait10Msec(55);

		servo[Block_Chuck] = 250;
		wait10Msec(55);

		servo[Spring_Release] = 250;
		wait10Msec(55);

		servo[Spring_Release] = 0;
		wait10Msec(55);

		servo[Block_Chuck] = 0;
		wait10Msec(55);
}
Пример #18
0
pos_t Look2AIPlayer::play(Board& board) {
	uchar self=board.turn();
	log_debug(board);
	assert(board.mobility()>=2);

	if (board.played_cnt()<10) {
		pos_t pos=OpeningBookPlayer::play(board);
		if (pos!=PASS) return pos;
	}

	pos_t best_pos=PASS;

	//两步棋后当前下子方的平均行动力
	//即两步棋后当前下子方的总行动力,除以一步棋后对手的总下法数(行动力)
	//可以理解为,一步棋后,对手的每种下法平均将给自己带来多少行动力
	float max_avg_mobility=-1;//根据最大化此值选择下法

	uint total_mobility1;//一步棋后对手的总下法数(行动力)
	uint total_mobility2;//两步棋后当前下子方的总行动力

	//找出下子之后使得对方行动力最低的一步走法
	for (pos_t pos = FIRST; pos < LAST; ++pos) {
		if (board.is_active(pos)) {

			if (best_pos==PASS) {//默认下法
				best_pos=pos;
			}

			Board think1=board;
			size_t eat1=think1.play(pos);//自己吃子数
			size_t mobility1=think1.mobility();//对手行动力

			if (mobility1==0) {//如果下某步棋后对手不能下子,则直接下这步棋
				best_pos=pos;
				goto play_look2;
			}

			if (BESIDE_GOOD_CORNER(pos)) {
				continue;
			}

			total_mobility1=mobility1;
			total_mobility2=0;

			bool oppo_has_good_move=false;
			for (pos_t pos2 = FIRST; pos2 < LAST; ++pos2) {
				if (think1.is_active(pos2)) {//对手走法

					if (IS_GOOD_CORNER(pos2)) {
						oppo_has_good_move=true;
					}

					Board think2=think1;
					size_t eat2=think2.play(pos2);//对手吃子数
					size_t mobility2=think2.mobility();//自己行动力
					total_mobility2+=mobility2;
				}
			}

			if (oppo_has_good_move) {
				continue;
			}

			float avg_mobility=float(total_mobility2)/total_mobility1;
			if (avg_mobility>max_avg_mobility) {
				max_avg_mobility=avg_mobility;
				best_pos=pos;
			}
		}
	}

play_look2:
	assert(best_pos!=PASS);
	log_info(COLOR(self)<<" Look2AIPlayer, play at "<<Move(self, best_pos));
	board.play(best_pos);
	return best_pos;
}
Пример #19
0
nsresult
SourceBuffer::Compact()
{
  mMutex.AssertCurrentThreadOwns();

  MOZ_ASSERT(mConsumerCount == 0, "Should have no consumers here");
  MOZ_ASSERT(mWaitingConsumers.Length() == 0, "Shouldn't have waiters");
  MOZ_ASSERT(mStatus, "Should be complete here");

  // Compact our waiting consumers list, since we're complete and no future
  // consumer will ever have to wait.
  mWaitingConsumers.Compact();

  // If we have no chunks, then there's nothing to compact.
  if (mChunks.Length() < 1) {
    return NS_OK;
  }

  // If we have one chunk, then we can compact if it has excess capacity.
  if (mChunks.Length() == 1 && mChunks[0].Length() == mChunks[0].Capacity()) {
    return NS_OK;
  }

  // We can compact our buffer. Determine the total length.
  size_t length = 0;
  for (uint32_t i = 0 ; i < mChunks.Length() ; ++i) {
    length += mChunks[i].Length();
  }

  // If our total length is zero (which means ExpectLength() got called, but no
  // data ever actually got written) then just empty our chunk list.
  if (MOZ_UNLIKELY(length == 0)) {
    mChunks.Clear();
    return NS_OK;
  }

  Maybe<Chunk> newChunk = CreateChunk(length, /* aRoundUp = */ false);
  if (MOZ_UNLIKELY(!newChunk || newChunk->AllocationFailed())) {
    NS_WARNING("Failed to allocate chunk for SourceBuffer compacting - OOM?");
    return NS_OK;
  }

  // Copy our old chunks into the new chunk.
  for (uint32_t i = 0 ; i < mChunks.Length() ; ++i) {
    size_t offset = newChunk->Length();
    MOZ_ASSERT(offset < newChunk->Capacity());
    MOZ_ASSERT(offset + mChunks[i].Length() <= newChunk->Capacity());

    memcpy(newChunk->Data() + offset, mChunks[i].Data(), mChunks[i].Length());
    newChunk->AddLength(mChunks[i].Length());
  }

  MOZ_ASSERT(newChunk->Length() == newChunk->Capacity(),
             "Compacted chunk has slack space");

  // Replace the old chunks with the new, compact chunk.
  mChunks.Clear();
  if (MOZ_UNLIKELY(NS_FAILED(AppendChunk(Move(newChunk))))) {
    return HandleError(NS_ERROR_OUT_OF_MEMORY);
  }
  mChunks.Compact();

  return NS_OK;
}
Пример #20
0
int main(int argc, char* argv[]) {
	char* locale = setlocale(LC_ALL, "German"); // Get the CRT's current locale.
	std::locale lollocale(locale);
	setlocale(LC_ALL, locale); // Restore the CRT.
	wcout.imbue(lollocale); // Now set the std::wcout to have the locale that we got from the CRT.

	wcout << L"Please input the path to your currentAdventure" << endl;

	wstring path;
	getline(wcin, path);

	wcout << L"Read in the file " << path << "..." << endl;

	auto currentAdventure = Adventure(path);

#ifdef _DEBUG
	wcout << L"You put in the following map" << endl;
	wcout << currentAdventure.CurrentMap->GetData() << endl;
#endif

	wcout << L"Parsing currentAdventure, please wait..." << endl;
	currentAdventure.CurrentMap->Parse();

	wcout << L"Let the game begin" << endl;
	system("cls");

	wcout << GREATINGTEXT << endl << endl;
	wcout << L" _____          _                   _                  " << endl;
	wcout << L"/__   \\_____  _| |___   _____ _ __ | |_ _   _ _ __ ___ " << endl;
	wcout << L"  / /\\/ _ \\ \\/ / __\\ \\ / / _ \\ '_ \\| __| | | | '__/ _ \\" << endl;
	wcout << L" / / |  __/>  <| |_ \\ V /  __/ | | | |_| |_| | | |  __/" << endl;
	wcout << L" \\/   \\___/_/\\_\\\\__| \\_/ \\___|_| |_|\\__|\\__,_|_|  \\___|" << endl;
	wcout << L"                                                       " << endl << endl;
	wcout << GOAL << endl << endl;
	wcout << GOODLUCK << endl;
	wcin.get();
	system("cls");

	currentAdventure.DrawMap();

	auto exit = false;
	while (!exit) {
		auto key = _getch();

		switch (currentAdventure.CurrentSituation) {
		case ::Walking:
			switch (key) {
			case 27:
				exit = true;
				break;
			case 80:
				currentAdventure.Move(::Down);
				break;
			case 72:
				currentAdventure.Move(::Up);
				break;
			case 77:
				currentAdventure.Move(::Right);
				break;
			case 75:
				currentAdventure.Move(::Left);
				break;
			}
			break;
		case ::Fighting:
			switch (key) {
			case 27:
				if (currentAdventure.CurrentFight->GetStatus() == Won) {
					currentAdventure.ExitFight();
				} else {
					currentAdventure.LooseFight();
				}
				break;
			case 97:
				currentAdventure.CurrentFight->Attack();
				break;
			case 98:
				currentAdventure.CurrentFight->Block();
				break;
			}
			break;
		default:
			switch (key) {
			case 27:
				exit = true;
				break;
			}
		}
	}
	return 0;
}
Пример #21
0
BOOL COXDragDockContext::Track()
{
    // don't handle if capture already set
    if (::GetCapture() != NULL)
        return FALSE;
	
    // set capture to the window which received this message
    m_pBar->SetCapture();
    ASSERT(m_pBar == CWnd::GetCapture());
	
    // get messages until capture lost or cancelled/accepted
    while(CWnd::GetCapture() == m_pBar)
	{
        MSG msg;
#ifndef _MAC
        if (!::GetMessage(&msg, NULL, 0, 0))
#else
			// don't allow yielding while tracking since we don't have LockWindowUpdate
			if (!PeekMessage(&msg, NULL, 0, 0, PM_REMOVE|PM_NOYIELD))
            continue;
        if (msg.message == WM_QUIT)
#endif
		{
            AfxPostQuitMessage(PtrToInt(msg.wParam));
            break;
		}
		
        switch (msg.message)
		{
            case WM_LBUTTONUP:		// drag finished 
                EndDrag();
                return TRUE;
				
            case WM_MOUSEMOVE:
                Move(msg.pt);
                break;
				
            case WM_KEYUP:
                OnKey((int)msg.wParam, FALSE);
                break;
				
            case WM_KEYDOWN:
				OnKey((int)msg.wParam, TRUE);
                if (msg.wParam == VK_ESCAPE)
					goto exit_cancel_drag;
                break;
				
			case WM_RBUTTONDOWN:
				goto exit_cancel_drag;
				
				// just dispatch rest of the messages
            default:
                DispatchMessage(&msg);
				break;
		}
	}
    
exit_cancel_drag:			// goto  - can't use break as we're inside a switch()    
	CancelDrag();
	return FALSE;
}
Пример #22
0
task main()
{
  initializeRobot();

  waitForStart(); // Wait for the beginning of autonomous phase.
  clearDebugStream();
  //leave zone
	Move(-9.66, 1);
	wait10Msec(10);
	Turn(28);
	wait10Msec(10);
	Move(-65, 1);
	wait10Msec(10);
	Turn(-23);
	wait10Msec(10);
	Move(-37, 0.9);
	wait10Msec(10);
	Move(-10, 0.2);
	//Precision Line-Up
	motor[lift] = 75;
	bool raising = false;
	nMotorEncoder[lift] = 0;
	while (abs(nMotorEncoder[lift]) < ULTRASONIC_RAISE)
	{
		if (TSreadState(touch) != 1 && !raising)
		{
			nMotorEncoder[lift] = 0;
			raising = true;
		}
		wait10Msec(10);
	}
	motor[lift] = 0;
	//while(true){}
	float Angle = 0;
	Angle = getUltraAngle();
	/*if (Angle == -1)
	Move(-5, 0.3);
	else if (Angle >= 86 && Angle <= 90)
	break;*/
	writeDebugStreamLine("%f", Angle);
	Turn(Angle - 90);
	float dist = -16;
	Move(dist, 0.25);

	//grab goal
	wait10Msec(30);
	servo[hook1] = 235;
	servo[hook2] = 30;
	wait10Msec(150);
	Turn(90 - Angle);
	wait10Msec(10);
	Move(117, 1);
	wait10Msec(10);
	Turn(-90);
	wait10Msec(10);
	Move(-25, 0.5);
	wait10Msec(10);
	//score
	motor[lift] = 75;
	nMotorEncoder[lift] = 0;
	while (abs(nMotorEncoder[lift]) < (LOW_GOAL - ULTRASONIC_RAISE))
	{
		wait10Msec(10);
	}
	motor[lift] = 0;
	Move(3, 0.2);
	wait10Msec(10);
	servo[output] = 250;
	wait10Msec(500);
	//release goal
	servo[hook1] = 0;
	servo[hook2] = 255;
	wait10Msec(300);
	Move(5, 1);
	wait10Msec(30);
	Turn(90);
}
Пример #23
0
void CPlayer::Update(float dt)
{
	CCommander::Update(dt);
	Select(dt);
	Move(dt);
}
Пример #24
0
 explicit GetGMPContentParentForAudioDecoderDone(UniquePtr<GetGMPAudioDecoderCallback>&& aCallback)
  : mCallback(Move(aCallback))
 {
 }
void
GMPStringListImpl::RelinquishData(nsTArray<nsCString>& aStrings)
{
  aStrings = Move(mStrings);
}
Пример #26
0
 explicit GetGMPContentParentForVideoEncoderDone(UniquePtr<GetGMPVideoEncoderCallback>&& aCallback)
  : mCallback(Move(aCallback))
 {
 }
Пример #27
0
// Divide wxHORIZONTALly or wxVERTICALly
bool wxDivisionShape::Divide(int direction)
{
  // Calculate existing top-left, bottom-right
  double x1 = (double)(GetX() - (GetWidth()/2.0));
  double y1 = (double)(GetY() - (GetHeight()/2.0));
  wxCompositeShape *compositeParent = (wxCompositeShape *)GetParent();
  double oldWidth = GetWidth();
  double oldHeight = GetHeight();
  if (Selected())
    Select(false);

  wxClientDC dc(GetCanvas());
  GetCanvas()->PrepareDC(dc);

  if (direction == wxVERTICAL)
  {
    // Dividing vertically means notionally putting a horizontal line through it.
    // Break existing piece into two.
    double newXPos1 = GetX();
    double newYPos1 = (double)(y1 + (GetHeight()/4.0));
    double newXPos2 = GetX();
    double newYPos2 = (double)(y1 + (3.0*GetHeight()/4.0));
    wxDivisionShape *newDivision = compositeParent->OnCreateDivision();
    newDivision->Show(true);

    Erase(dc);

    // Anything adjoining the bottom of this division now adjoins the
    // bottom of the new division.
    wxNode *node = compositeParent->GetDivisions().GetFirst();
    while (node)
    {
      wxDivisionShape *obj = (wxDivisionShape *)node->GetData();
      if (obj->GetTopSide() == this)
        obj->SetTopSide(newDivision);
      node = node->GetNext();
    }
    newDivision->SetTopSide(this);
    newDivision->SetBottomSide(m_bottomSide);
    newDivision->SetLeftSide(m_leftSide);
    newDivision->SetRightSide(m_rightSide);
    m_bottomSide = newDivision;

    compositeParent->GetDivisions().Append(newDivision);

    // CHANGE: Need to insert this division at start of divisions in the object
    // list, because e.g.:
    // 1) Add division
    // 2) Add contained object
    // 3) Add division
    // Division is now receiving mouse events _before_ the contained object,
    // because it was added last (on top of all others)

    // Add after the image that visualizes the container
    compositeParent->AddChild(newDivision, compositeParent->FindContainerImage());

    m_handleSide = DIVISION_SIDE_BOTTOM;
    newDivision->SetHandleSide(DIVISION_SIDE_TOP);

    SetSize(oldWidth, (double)(oldHeight/2.0));
    Move(dc, newXPos1, newYPos1);

    newDivision->SetSize(oldWidth, (double)(oldHeight/2.0));
    newDivision->Move(dc, newXPos2, newYPos2);
  }
  else
  {
    // Dividing horizontally means notionally putting a vertical line through it.
    // Break existing piece into two.
    double newXPos1 = (double)(x1 + (GetWidth()/4.0));
    double newYPos1 = GetY();
    double newXPos2 = (double)(x1 + (3.0*GetWidth()/4.0));
    double newYPos2 = GetY();
    wxDivisionShape *newDivision = compositeParent->OnCreateDivision();
    newDivision->Show(true);

    Erase(dc);

    // Anything adjoining the left of this division now adjoins the
    // left of the new division.
    wxNode *node = compositeParent->GetDivisions().GetFirst();
    while (node)
    {
      wxDivisionShape *obj = (wxDivisionShape *)node->GetData();
      if (obj->GetLeftSide() == this)
        obj->SetLeftSide(newDivision);
      node = node->GetNext();
    }
    newDivision->SetTopSide(m_topSide);
    newDivision->SetBottomSide(m_bottomSide);
    newDivision->SetLeftSide(this);
    newDivision->SetRightSide(m_rightSide);
    m_rightSide = newDivision;

    compositeParent->GetDivisions().Append(newDivision);
    compositeParent->AddChild(newDivision, compositeParent->FindContainerImage());

    m_handleSide = DIVISION_SIDE_RIGHT;
    newDivision->SetHandleSide(DIVISION_SIDE_LEFT);

    SetSize((double)(oldWidth/2.0), oldHeight);
    Move(dc, newXPos1, newYPos1);

    newDivision->SetSize((double)(oldWidth/2.0), oldHeight);
    newDivision->Move(dc, newXPos2, newYPos2);
  }
  if (compositeParent->Selected())
  {
    compositeParent->DeleteControlPoints(& dc);
    compositeParent->MakeControlPoints();
    compositeParent->MakeMandatoryControlPoints();
  }
  compositeParent->Draw(dc);
  return true;
}
Пример #28
0
 explicit GetGMPContentParentForDecryptorDone(UniquePtr<GetGMPDecryptorCallback>&& aCallback)
  : mCallback(Move(aCallback))
 {
 }
Пример #29
0
 void BoundingBox::SetPosition (const Vector2& position)
 {
   Move (position - GetPosition ());
 }
Пример #30
0
MediaResult
VorbisDataDecoder::DoDecode(MediaRawData* aSample)
{
  MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn());

  const unsigned char* aData = aSample->Data();
  size_t aLength = aSample->Size();
  int64_t aOffset = aSample->mOffset;
  int64_t aTstampUsecs = aSample->mTime;
  int64_t aTotalFrames = 0;

  MOZ_ASSERT(mPacketCount >= 3);

  if (!mLastFrameTime || mLastFrameTime.ref() != aSample->mTime) {
    // We are starting a new block.
    mFrames = 0;
    mLastFrameTime = Some(aSample->mTime);
  }

  ogg_packet pkt = InitVorbisPacket(aData, aLength, false, aSample->mEOS,
                                    aSample->mTimecode, mPacketCount++);

  int err = vorbis_synthesis(&mVorbisBlock, &pkt);
  if (err) {
    return MediaResult(NS_ERROR_DOM_MEDIA_DECODE_ERR,
                       RESULT_DETAIL("vorbis_synthesis:%d", err));
  }

  err = vorbis_synthesis_blockin(&mVorbisDsp, &mVorbisBlock);
  if (err) {
    return MediaResult(NS_ERROR_DOM_MEDIA_DECODE_ERR,
                       RESULT_DETAIL("vorbis_synthesis_blockin:%d", err));
  }

  VorbisPCMValue** pcm = 0;
  int32_t frames = vorbis_synthesis_pcmout(&mVorbisDsp, &pcm);
  if (frames == 0) {
    return NS_OK;
  }
  while (frames > 0) {
    uint32_t channels = mVorbisDsp.vi->channels;
    uint32_t rate = mVorbisDsp.vi->rate;
    AlignedAudioBuffer buffer(frames*channels);
    if (!buffer) {
      return MediaResult(NS_ERROR_OUT_OF_MEMORY, __func__);
    }
    for (uint32_t j = 0; j < channels; ++j) {
      VorbisPCMValue* channel = pcm[j];
      for (uint32_t i = 0; i < uint32_t(frames); ++i) {
        buffer[i*channels + j] = MOZ_CONVERT_VORBIS_SAMPLE(channel[i]);
      }
    }

    CheckedInt64 duration = FramesToUsecs(frames, rate);
    if (!duration.isValid()) {
      return MediaResult(NS_ERROR_DOM_MEDIA_OVERFLOW_ERR,
                         RESULT_DETAIL("Overflow converting audio duration"));
    }
    CheckedInt64 total_duration = FramesToUsecs(mFrames, rate);
    if (!total_duration.isValid()) {
      return MediaResult(
        NS_ERROR_DOM_MEDIA_OVERFLOW_ERR,
        RESULT_DETAIL("Overflow converting audio total_duration"));
    }

    CheckedInt64 time = total_duration + aTstampUsecs;
    if (!time.isValid()) {
      return MediaResult(
        NS_ERROR_DOM_MEDIA_OVERFLOW_ERR,
        RESULT_DETAIL("Overflow adding total_duration and aTstampUsecs"));
    };

    if (!mAudioConverter) {
      AudioConfig in(AudioConfig::ChannelLayout(channels, VorbisLayout(channels)),
                     rate);
      AudioConfig out(channels, rate);
      if (!in.IsValid() || !out.IsValid()) {
        return MediaResult(
          NS_ERROR_DOM_MEDIA_FATAL_ERR,
          RESULT_DETAIL("Invalid channel layout:%u", channels));
      }
      mAudioConverter = MakeUnique<AudioConverter>(in, out);
    }
    MOZ_ASSERT(mAudioConverter->CanWorkInPlace());
    AudioSampleBuffer data(Move(buffer));
    data = mAudioConverter->Process(Move(data));

    aTotalFrames += frames;
    mCallback->Output(new AudioData(aOffset,
                                    time.value(),
                                    duration.value(),
                                    frames,
                                    data.Forget(),
                                    channels,
                                    rate));
    mFrames += frames;
    err = vorbis_synthesis_read(&mVorbisDsp, frames);
    if (err) {
      return MediaResult(NS_ERROR_DOM_MEDIA_DECODE_ERR,
                         RESULT_DETAIL("vorbis_synthesis_read:%d", err));
    }

    frames = vorbis_synthesis_pcmout(&mVorbisDsp, &pcm);
  }

  return NS_OK;
}