Beispiel #1
0
nsresult
AppleATDecoder::SetupDecoder(MediaRawData* aSample)
{
  MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn());

  if (mFormatID == kAudioFormatMPEG4AAC &&
      mConfig.mExtendedProfile == 2) {
    // Check for implicit SBR signalling if stream is AAC-LC
    // This will provide us with an updated magic cookie for use with
    // GetInputAudioDescription.
    if (NS_SUCCEEDED(GetImplicitAACMagicCookie(aSample)) &&
        !mMagicCookie.Length()) {
      // nothing found yet, will try again later
      return NS_ERROR_NOT_INITIALIZED;
    }
    // An error occurred, fallback to using default stream description
  }

  LOG("Initializing Apple AudioToolbox decoder");

  AudioStreamBasicDescription inputFormat;
  PodZero(&inputFormat);
  nsresult rv =
    GetInputAudioDescription(inputFormat,
                             mMagicCookie.Length() ?
                                 mMagicCookie : *mConfig.mExtraData);
  if (NS_FAILED(rv)) {
    return rv;
  }
  // Fill in the output format manually.
  PodZero(&mOutputFormat);
  mOutputFormat.mFormatID = kAudioFormatLinearPCM;
  mOutputFormat.mSampleRate = inputFormat.mSampleRate;
  mOutputFormat.mChannelsPerFrame = inputFormat.mChannelsPerFrame;
#if defined(MOZ_SAMPLE_TYPE_FLOAT32)
  mOutputFormat.mBitsPerChannel = 32;
  mOutputFormat.mFormatFlags =
    kLinearPCMFormatFlagIsFloat |
    0;
#elif defined(MOZ_SAMPLE_TYPE_S16)
  mOutputFormat.mBitsPerChannel = 16;
  mOutputFormat.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger | 0;
#else
# error Unknown audio sample type
#endif
  // Set up the decoder so it gives us one sample per frame
  mOutputFormat.mFramesPerPacket = 1;
  mOutputFormat.mBytesPerPacket = mOutputFormat.mBytesPerFrame
        = mOutputFormat.mChannelsPerFrame * mOutputFormat.mBitsPerChannel / 8;

  OSStatus status = AudioConverterNew(&inputFormat, &mOutputFormat, &mConverter);
  if (status) {
    LOG("Error %d constructing AudioConverter", status);
    mConverter = nullptr;
    return NS_ERROR_FAILURE;
  }

  if (NS_FAILED(SetupChannelLayout())) {
    NS_WARNING("Couldn't retrieve channel layout, will use default layout");
  }

  return NS_OK;
}
NS_IMETHODIMP
FetchDriver::OnStartRequest(nsIRequest* aRequest,
                            nsISupports* aContext)
{
  workers::AssertIsOnMainThread();
  MOZ_ASSERT(!mPipeOutputStream);
  MOZ_ASSERT(mObserver);
  nsresult rv;
  aRequest->GetStatus(&rv);
  if (NS_WARN_IF(NS_FAILED(rv))) {
    FailWithNetworkError();
    return rv;
  }

  nsCOMPtr<nsIHttpChannel> channel = do_QueryInterface(aRequest);
  // For now we only support HTTP.
  MOZ_ASSERT(channel);

  aRequest->GetStatus(&rv);
  if (NS_WARN_IF(NS_FAILED(rv))) {
    FailWithNetworkError();
    return rv;
  }

  uint32_t responseStatus;
  channel->GetResponseStatus(&responseStatus);

  nsAutoCString statusText;
  channel->GetResponseStatusText(statusText);

  nsRefPtr<InternalResponse> response = new InternalResponse(responseStatus, statusText);

  nsRefPtr<FillResponseHeaders> visitor = new FillResponseHeaders(response);
  rv = channel->VisitResponseHeaders(visitor);
  if (NS_WARN_IF(NS_FAILED(rv))) {
    NS_WARNING("Failed to visit all headers.");
  }

  // We open a pipe so that we can immediately set the pipe's read end as the
  // response's body. Setting the segment size to UINT32_MAX means that the
  // pipe has infinite space. The nsIChannel will continue to buffer data in
  // xpcom events even if we block on a fixed size pipe.  It might be possible
  // to suspend the channel and then resume when there is space available, but
  // for now use an infinite pipe to avoid blocking.
  nsCOMPtr<nsIInputStream> pipeInputStream;
  rv = NS_NewPipe(getter_AddRefs(pipeInputStream),
                  getter_AddRefs(mPipeOutputStream),
                  0, /* default segment size */
                  UINT32_MAX /* infinite pipe */,
                  true /* non-blocking input, otherwise you deadlock */,
                  false /* blocking output, since the pipe is 'in'finite */ );
  if (NS_WARN_IF(NS_FAILED(rv))) {
    FailWithNetworkError();
    // Cancel request.
    return rv;
  }
  response->SetBody(pipeInputStream);

  nsCOMPtr<nsISupports> securityInfo;
  rv = channel->GetSecurityInfo(getter_AddRefs(securityInfo));
  if (securityInfo) {
    response->SetSecurityInfo(securityInfo);
  }

  // Resolves fetch() promise which may trigger code running in a worker.  Make
  // sure the Response is fully initialized before calling this.
  mResponse = BeginAndGetFilteredResponse(response);

  nsCOMPtr<nsIEventTarget> sts = do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID, &rv);
  if (NS_WARN_IF(NS_FAILED(rv))) {
    FailWithNetworkError();
    // Cancel request.
    return rv;
  }

  // Try to retarget off main thread.
  nsCOMPtr<nsIThreadRetargetableRequest> rr = do_QueryInterface(aRequest);
  if (rr) {
    rr->RetargetDeliveryTo(sts);
  }
  return NS_OK;
}
int
FFmpegH264Decoder::AllocateYUV420PVideoBuffer(AVCodecContext* aCodecContext,
                                              AVFrame* aFrame)
{
  // Older versions of ffmpeg require that edges be allocated* around* the
  // actual image.
  int edgeWidth = avcodec_get_edge_width();
  int decodeWidth = aCodecContext->width + edgeWidth * 2;
  int decodeHeight = aCodecContext->height + edgeWidth * 2;

  // Align width and height to possibly speed up decode.
  int stride_align[AV_NUM_DATA_POINTERS];
  avcodec_align_dimensions2(aCodecContext, &decodeWidth, &decodeHeight,
                            stride_align);

  // Get strides for each plane.
  av_image_fill_linesizes(aFrame->linesize, aCodecContext->pix_fmt,
                          decodeWidth);

  // Let FFmpeg set up its YUV plane pointers and tell us how much memory we
  // need.
  // Note that we're passing |nullptr| here as the base address as we haven't
  // allocated our image yet. We will adjust |aFrame->data| below.
  size_t allocSize =
    av_image_fill_pointers(aFrame->data, aCodecContext->pix_fmt, decodeHeight,
                           nullptr /* base address */, aFrame->linesize);

  nsRefPtr<Image> image =
    mImageContainer->CreateImage(ImageFormat::PLANAR_YCBCR);
  PlanarYCbCrImage* ycbcr = reinterpret_cast<PlanarYCbCrImage*>(image.get());
  uint8_t* buffer = ycbcr->AllocateAndGetNewBuffer(allocSize);

  if (!buffer) {
    NS_WARNING("Failed to allocate buffer for FFmpeg video decoding");
    return -1;
  }

  // Now that we've allocated our image, we can add its address to the offsets
  // set by |av_image_fill_pointers| above. We also have to add |edgeWidth|
  // pixels of padding here.
  for (uint32_t i = 0; i < AV_NUM_DATA_POINTERS; i++) {
    // The C planes are half the resolution of the Y plane, so we need to halve
    // the edge width here.
    uint32_t planeEdgeWidth = edgeWidth / (i ? 2 : 1);

    // Add buffer offset, plus a horizontal bar |edgeWidth| pixels high at the
    // top of the frame, plus |edgeWidth| pixels from the left of the frame.
    aFrame->data[i] += reinterpret_cast<ptrdiff_t>(
      buffer + planeEdgeWidth * aFrame->linesize[i] + planeEdgeWidth);
  }

  // Unused, but needs to be non-zero to keep ffmpeg happy.
  aFrame->type = GECKO_FRAME_TYPE;

  aFrame->extended_data = aFrame->data;
  aFrame->width = aCodecContext->width;
  aFrame->height = aCodecContext->height;

  mozilla::layers::PlanarYCbCrData data;
  PlanarYCbCrDataFromAVFrame(data, aFrame);
  ycbcr->SetDataNoCopy(data);

  mCurrentImage.swap(image);

  return 0;
}
Beispiel #4
0
nsresult
nsSVGClipPathFrame::ClipPaint(nsSVGRenderState* aContext,
                              nsIFrame* aParent,
                              const gfxMatrix &aMatrix)
{
  // If the flag is set when we get here, it means this clipPath frame
  // has already been used painting the current clip, and the document
  // has a clip reference loop.
  if (mInUse) {
    NS_WARNING("Clip loop detected!");
    return NS_OK;
  }
  AutoClipPathReferencer clipRef(this);

  mClipParent = aParent;
  if (mClipParentMatrix) {
    *mClipParentMatrix = aMatrix;
  } else {
    mClipParentMatrix = new gfxMatrix(aMatrix);
  }

  bool isTrivial = IsTrivial();

  nsAutoSVGRenderMode mode(aContext,
                           isTrivial ? nsSVGRenderState::CLIP
                                     : nsSVGRenderState::CLIP_MASK);


  gfxContext *gfx = aContext->GetGfxContext();

  nsSVGClipPathFrame *clipPathFrame =
    nsSVGEffects::GetEffectProperties(this).GetClipPathFrame(nsnull);
  bool referencedClipIsTrivial;
  if (clipPathFrame) {
    referencedClipIsTrivial = clipPathFrame->IsTrivial();
    gfx->Save();
    if (referencedClipIsTrivial) {
      clipPathFrame->ClipPaint(aContext, aParent, aMatrix);
    } else {
      gfx->PushGroup(gfxASurface::CONTENT_ALPHA);
    }
  }

  for (nsIFrame* kid = mFrames.FirstChild(); kid;
       kid = kid->GetNextSibling()) {
    nsISVGChildFrame* SVGFrame = do_QueryFrame(kid);
    if (SVGFrame) {
      // The CTM of each frame referencing us can be different.
      SVGFrame->NotifySVGChanged(nsISVGChildFrame::SUPPRESS_INVALIDATION | 
                                 nsISVGChildFrame::TRANSFORM_CHANGED);

      bool isOK = true;
      nsSVGClipPathFrame *clipPathFrame =
        nsSVGEffects::GetEffectProperties(kid).GetClipPathFrame(&isOK);
      if (!isOK) {
        continue;
      }

      bool isTrivial;

      if (clipPathFrame) {
        isTrivial = clipPathFrame->IsTrivial();
        gfx->Save();
        if (isTrivial) {
          clipPathFrame->ClipPaint(aContext, aParent, aMatrix);
        } else {
          gfx->PushGroup(gfxASurface::CONTENT_ALPHA);
        }
      }

      SVGFrame->PaintSVG(aContext, nsnull);

      if (clipPathFrame) {
        if (!isTrivial) {
          gfx->PopGroupToSource();

          nsRefPtr<gfxPattern> clipMaskSurface;
          gfx->PushGroup(gfxASurface::CONTENT_ALPHA);

          clipPathFrame->ClipPaint(aContext, aParent, aMatrix);
          clipMaskSurface = gfx->PopGroup();

          if (clipMaskSurface) {
            gfx->Mask(clipMaskSurface);
          }
        }
        gfx->Restore();
      }
    }
  }

  if (clipPathFrame) {
    if (!referencedClipIsTrivial) {
      gfx->PopGroupToSource();

      nsRefPtr<gfxPattern> clipMaskSurface;
      gfx->PushGroup(gfxASurface::CONTENT_ALPHA);

      clipPathFrame->ClipPaint(aContext, aParent, aMatrix);
      clipMaskSurface = gfx->PopGroup();

      if (clipMaskSurface) {
        gfx->Mask(clipMaskSurface);
      }
    }
    gfx->Restore();
  }

  if (isTrivial) {
    gfx->Clip();
    gfx->NewPath();
  }

  return NS_OK;
}
FFmpegVideoDecoder<LIBAV_VER>::DecodeResult
FFmpegVideoDecoder<LIBAV_VER>::DoDecodeFrame(MediaRawData* aSample,
                                            uint8_t* aData, int aSize)
{
  MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn());

  AVPacket packet;
  mLib->av_init_packet(&packet);

  packet.data = aData;
  packet.size = aSize;
  packet.dts = aSample->mTimecode;
  packet.pts = aSample->mTime;
  packet.flags = aSample->mKeyframe ? AV_PKT_FLAG_KEY : 0;
  packet.pos = aSample->mOffset;

  // LibAV provides no API to retrieve the decoded sample's duration.
  // (FFmpeg >= 1.0 provides av_frame_get_pkt_duration)
  // As such we instead use a map using the dts as key that we will retrieve
  // later.
  // The map will have a typical size of 16 entry.
  mDurationMap.Insert(aSample->mTimecode, aSample->mDuration);

  if (!PrepareFrame()) {
    NS_WARNING("FFmpeg h264 decoder failed to allocate frame.");
    mCallback->Error();
    return DecodeResult::DECODE_ERROR;
  }

  // Required with old version of FFmpeg/LibAV
  mFrame->reordered_opaque = AV_NOPTS_VALUE;

  int decoded;
  int bytesConsumed =
    mLib->avcodec_decode_video2(mCodecContext, mFrame, &decoded, &packet);

  FFMPEG_LOG("DoDecodeFrame:decode_video: rv=%d decoded=%d "
             "(Input: pts(%lld) dts(%lld) Output: pts(%lld) "
             "opaque(%lld) pkt_pts(%lld) pkt_dts(%lld))",
             bytesConsumed, decoded, packet.pts, packet.dts, mFrame->pts,
             mFrame->reordered_opaque, mFrame->pkt_pts, mFrame->pkt_dts);

  if (bytesConsumed < 0) {
    NS_WARNING("FFmpeg video decoder error.");
    mCallback->Error();
    return DecodeResult::DECODE_ERROR;
  }

  // If we've decoded a frame then we need to output it
  if (decoded) {
    int64_t pts = mPtsContext.GuessCorrectPts(mFrame->pkt_pts, mFrame->pkt_dts);
    FFMPEG_LOG("Got one frame output with pts=%lld opaque=%lld",
               pts, mCodecContext->reordered_opaque);
    // Retrieve duration from dts.
    // We use the first entry found matching this dts (this is done to
    // handle damaged file with multiple frames with the same dts)

    int64_t duration;
    if (!mDurationMap.Find(mFrame->pkt_dts, duration)) {
      NS_WARNING("Unable to retrieve duration from map");
      duration = aSample->mDuration;
      // dts are probably incorrectly reported ; so clear the map as we're
      // unlikely to find them in the future anyway. This also guards
      // against the map becoming extremely big.
      mDurationMap.Clear();
    }

    VideoData::YCbCrBuffer b;
    b.mPlanes[0].mData = mFrame->data[0];
    b.mPlanes[1].mData = mFrame->data[1];
    b.mPlanes[2].mData = mFrame->data[2];

    b.mPlanes[0].mStride = mFrame->linesize[0];
    b.mPlanes[1].mStride = mFrame->linesize[1];
    b.mPlanes[2].mStride = mFrame->linesize[2];

    b.mPlanes[0].mOffset = b.mPlanes[0].mSkip = 0;
    b.mPlanes[1].mOffset = b.mPlanes[1].mSkip = 0;
    b.mPlanes[2].mOffset = b.mPlanes[2].mSkip = 0;

    b.mPlanes[0].mWidth = mFrame->width;
    b.mPlanes[0].mHeight = mFrame->height;
    if (mCodecContext->pix_fmt == AV_PIX_FMT_YUV444P) {
      b.mPlanes[1].mWidth = b.mPlanes[2].mWidth = mFrame->width;
      b.mPlanes[1].mHeight = b.mPlanes[2].mHeight = mFrame->height;
    } else {
      b.mPlanes[1].mWidth = b.mPlanes[2].mWidth = (mFrame->width + 1) >> 1;
      b.mPlanes[1].mHeight = b.mPlanes[2].mHeight = (mFrame->height + 1) >> 1;
    }

    RefPtr<VideoData> v = VideoData::Create(mInfo,
                                            mImageContainer,
                                            aSample->mOffset,
                                            pts,
                                            duration,
                                            b,
                                            !!mFrame->key_frame,
                                            -1,
                                            mInfo.ScaledImageRect(mFrame->width,
                                                                  mFrame->height));

    if (!v) {
      NS_WARNING("image allocation error.");
      mCallback->Error();
      return DecodeResult::DECODE_ERROR;
    }
    mCallback->Output(v);
    return DecodeResult::DECODE_FRAME;
  }
  return DecodeResult::DECODE_NO_FRAME;
}
NS_IMETHODIMP
sbDeviceFirmwareUpdater::OnDeviceEvent(sbIDeviceEvent *aEvent) 
{
  LOG(("[sbDeviceFirmwareUpdater] - OnDeviceEvent"));

  NS_ENSURE_ARG_POINTER(aEvent);

  nsCOMPtr<sbIDevice> device;
  nsresult rv = aEvent->GetOrigin(getter_AddRefs(device));
  NS_ENSURE_SUCCESS(rv, rv);

  LOG(("[sbDeviceFirmwareUpdater] - Origin Device 0x%X", device.get()));

  nsCOMPtr<sbIDeviceFirmwareHandler> handler = GetRunningHandler(device);
  NS_ENSURE_TRUE(handler, NS_OK);

  PRUint32 eventType = 0;
  rv = aEvent->GetType(&eventType);
  NS_ENSURE_SUCCESS(rv, rv);

  nsAutoMonitor mon(mMonitor);
  sbDeviceFirmwareHandlerStatus *handlerStatus = GetHandlerStatus(handler);
  NS_ENSURE_TRUE(handlerStatus, NS_ERROR_UNEXPECTED);
  
  sbDeviceFirmwareHandlerStatus::handleroperation_t operation = 
    sbDeviceFirmwareHandlerStatus::OP_NONE;
  rv = handlerStatus->GetOperation(&operation);
  NS_ENSURE_SUCCESS(rv, rv);

  sbDeviceFirmwareHandlerStatus::handlerstatus_t status = 
    sbDeviceFirmwareHandlerStatus::STATUS_NONE;
  rv = handlerStatus->GetStatus(&status);
  NS_ENSURE_SUCCESS(rv, rv);

  PRBool removeListener = PR_FALSE;

  switch(operation) {
    case sbDeviceFirmwareHandlerStatus::OP_REFRESH: {
      LOG(("[sbDeviceFirmwareUpdater] - OP_REFRESH"));

      if(eventType == sbIDeviceEvent::EVENT_FIRMWARE_CFU_START &&
         status == sbDeviceFirmwareHandlerStatus::STATUS_WAITING_FOR_START) {
        rv = handlerStatus->SetStatus(sbDeviceFirmwareHandlerStatus::STATUS_RUNNING);
        NS_ENSURE_SUCCESS(rv, rv);
      }
      else if((eventType == sbIDeviceEvent::EVENT_FIRMWARE_CFU_END ||
               eventType == sbIDeviceEvent::EVENT_FIRMWARE_CFU_ERROR) &&
              status == sbDeviceFirmwareHandlerStatus::STATUS_RUNNING) {
        rv = handlerStatus->SetStatus(sbDeviceFirmwareHandlerStatus::STATUS_FINISHED);
        NS_ENSURE_SUCCESS(rv, rv);

        removeListener = PR_TRUE;

        // Check to see if the device requires recovery mode
        rv = RequiresRecoveryMode(device, handler);
        NS_ENSURE_SUCCESS(rv, rv);
      }
    }
    break;

    case sbDeviceFirmwareHandlerStatus::OP_DOWNLOAD: {
      LOG(("[sbDeviceFirmwareUpdater] - OP_DOWNLOAD"));

      if(eventType == sbIDeviceEvent::EVENT_FIRMWARE_DOWNLOAD_START &&
         status == sbDeviceFirmwareHandlerStatus::STATUS_WAITING_FOR_START) {
        rv = handlerStatus->SetStatus(sbDeviceFirmwareHandlerStatus::STATUS_RUNNING);
        NS_ENSURE_SUCCESS(rv, rv);
      }
      else if(eventType == sbIDeviceEvent::EVENT_FIRMWARE_DOWNLOAD_END &&
              status == sbDeviceFirmwareHandlerStatus::STATUS_RUNNING) {
        rv = handlerStatus->SetStatus(sbDeviceFirmwareHandlerStatus::STATUS_FINISHED);
        NS_ENSURE_SUCCESS(rv, rv);

        removeListener = PR_TRUE;
      }
    }
    break;

    case sbDeviceFirmwareHandlerStatus::OP_UPDATE:
    case sbDeviceFirmwareHandlerStatus::OP_RECOVERY: {
      LOG(("[sbDeviceFirmwareUpdater] - OP_UPDATE or OP_RECOVERY"));
      
      if(eventType == sbIDeviceEvent::EVENT_FIRMWARE_UPDATE_START &&
         status == sbDeviceFirmwareHandlerStatus::STATUS_WAITING_FOR_START) {
          rv = handlerStatus->SetStatus(sbDeviceFirmwareHandlerStatus::STATUS_RUNNING);
          NS_ENSURE_SUCCESS(rv, rv);
      }
      else if(eventType == sbIDeviceEvent::EVENT_FIRMWARE_UPDATE_END &&
              status == sbDeviceFirmwareHandlerStatus::STATUS_RUNNING) {
          rv = handlerStatus->SetStatus(sbDeviceFirmwareHandlerStatus::STATUS_FINISHED);
          NS_ENSURE_SUCCESS(rv, rv);

          removeListener = PR_TRUE;
      }
      else if(eventType == sbIDeviceEvent::EVENT_FIRMWARE_NEEDREC_ERROR) {
        // Reset status when we get a NEED RECOVERY error to enable normal
        // operation after device is reconnected in recovery mode.
        rv = handlerStatus->SetStatus(sbDeviceFirmwareHandlerStatus::STATUS_NONE);
        NS_ENSURE_SUCCESS(rv, rv);
      }
    }
    break;

    default:
      NS_WARNING("Unsupported operation");
  }

  mon.Exit();

  if(removeListener) {
    nsCOMPtr<sbIDeviceEventTarget> eventTarget = 
      do_QueryInterface(device, &rv);
    NS_ENSURE_SUCCESS(rv, rv);

    rv = eventTarget->RemoveEventListener(this);
    NS_ENSURE_SUCCESS(rv, rv);
  }

  return NS_OK;
}
void
nsPicoService::Init()
{
    MOZ_ASSERT(!NS_IsMainThread());
    MOZ_ASSERT(!mInitialized);

    if (!sPicoApi.Init()) {
        NS_WARNING("Failed to initialize pico library");
        return;
    }

    // Use environment variable, or default android/b2g path
    nsAutoCString langPath(PR_GetEnv("PICO_LANG_PATH"));

    if (langPath.IsEmpty()) {
        langPath.AssignLiteral(GONK_PICO_LANG_PATH);
    }

    nsCOMPtr<nsIFile> voicesDir;
    NS_NewNativeLocalFile(langPath, true, getter_AddRefs(voicesDir));

    nsCOMPtr<nsISimpleEnumerator> dirIterator;
    nsresult rv = voicesDir->GetDirectoryEntries(getter_AddRefs(dirIterator));

    if (NS_FAILED(rv)) {
        NS_WARNING(nsPrintfCString("Failed to get contents of directory: %s", langPath.get()).get());
        return;
    }

    bool hasMoreElements = false;
    rv = dirIterator->HasMoreElements(&hasMoreElements);
    MOZ_ASSERT(NS_SUCCEEDED(rv));

    MonitorAutoLock autoLock(mVoicesMonitor);

    while (hasMoreElements && NS_SUCCEEDED(rv)) {
        nsCOMPtr<nsISupports> supports;
        rv = dirIterator->GetNext(getter_AddRefs(supports));
        MOZ_ASSERT(NS_SUCCEEDED(rv));

        nsCOMPtr<nsIFile> voiceFile = do_QueryInterface(supports);
        MOZ_ASSERT(voiceFile);

        nsAutoCString leafName;
        voiceFile->GetNativeLeafName(leafName);

        nsAutoString lang;

        if (GetVoiceFileLanguage(leafName, lang)) {
            nsAutoString uri;
            uri.AssignLiteral("urn:moz-tts:pico:");
            uri.Append(lang);

            bool found = false;
            PicoVoice* voice = mVoices.GetWeak(uri, &found);

            if (!found) {
                voice = new PicoVoice(lang);
                mVoices.Put(uri, voice);
            }

            // Each voice consists of two lingware files: A language resource file,
            // suffixed by _ta.bin, and a speaker resource file, suffixed by _sb.bin.
            // We currently assume that there is a pair of files for each language.
            if (StringEndsWith(leafName, NS_LITERAL_CSTRING("_ta.bin"))) {
                rv = voiceFile->GetPersistentDescriptor(voice->mTaFile);
                MOZ_ASSERT(NS_SUCCEEDED(rv));
            } else if (StringEndsWith(leafName, NS_LITERAL_CSTRING("_sg.bin"))) {
                rv = voiceFile->GetPersistentDescriptor(voice->mSgFile);
                MOZ_ASSERT(NS_SUCCEEDED(rv));
            }
        }

        rv = dirIterator->HasMoreElements(&hasMoreElements);
    }

    NS_DispatchToMainThread(NS_NewRunnableMethod(this, &nsPicoService::RegisterVoices));
}
/*
 * Query the font used for various CSS properties (aID) from the system.
 * For OS/2, only very few fonts are defined in the system, so most of the IDs
 * resolve to the same system font.
 * The font queried will give back a string like
 *    9.WarpSans Bold
 *    12.Times New Roman Bold Italic
 *    10.Times New Roman.Strikeout.Underline
 *    20.Bitstream Vera Sans Mono Obli
 * (always restricted to 32 chars, at least before the second dot)
 * We use the value before the dot as the font size (in pt, and convert it to
 * px using the screen resolution) and then try to use the rest of the string
 * to determine the font style from it.
 */
bool
nsLookAndFeel::GetFont(FontID aID, nsString& aFontName,
                       gfxFontStyle& aFontStyle)
{
  char szFontNameSize[MAXNAMEL];

  switch (aID)
    {
    case eFont_Icon:
      QueryFontFromINI("IconText", szFontNameSize, MAXNAMEL);
      break;

    case eFont_Menu:
      QueryFontFromINI("Menus", szFontNameSize, MAXNAMEL);
      break;

    case eFont_Caption:
    case eFont_MessageBox:
    case eFont_SmallCaption:
    case eFont_StatusBar:
    case eFont_Tooltips:
    case eFont_Widget:

    case eFont_Window:      // css3
    case eFont_Document:
    case eFont_Workspace:
    case eFont_Desktop:
    case eFont_Info:
    case eFont_Dialog:
    case eFont_Button:
    case eFont_PullDownMenu:
    case eFont_List:
    case eFont_Field:
      QueryFontFromINI("WindowText", szFontNameSize, MAXNAMEL);
      break;

    default:
      NS_WARNING("None of the listed font types, using WarpSans");
      if (!IsDBCS()) {
        strcpy(szFontNameSize, "9.WarpSans");
      } else {
        strcpy(szFontNameSize, "9.WarpSans Combined");
      }
    }

  char *szFacename = strchr(szFontNameSize, '.');
  if (!szFacename || (*(szFacename++) == '\0'))
    return false;

  // local DPI for size will be taken into account below
  aFontStyle.size = atof(szFontNameSize);

  // determine DPI resolution of screen device to compare compute
  // font size in pixels
  HPS ps = WinGetScreenPS(HWND_DESKTOP);
  HDC dc = GpiQueryDevice(ps);
  // effective vertical resolution in DPI
  LONG vertScreenRes = 120; // assume 120 dpi as default
  DevQueryCaps(dc, CAPS_VERTICAL_FONT_RES, 1, &vertScreenRes);
  WinReleasePS(ps);

  // now scale to make pixels from points (1 pt = 1/72in)
  aFontStyle.size *= vertScreenRes / 72.0;

  NS_ConvertUTF8toUTF16 fontFace(szFacename);
  int pos = 0;

  // this is a system font in any case
  aFontStyle.systemFont = true;

  // bold fonts should have " Bold" in their names, at least we hope that they
  // do, otherwise it's bad luck
  NS_NAMED_LITERAL_CSTRING(spcBold, " Bold");
  if ((pos = fontFace.Find(spcBold.get(), false, 0, -1)) > -1) {
    aFontStyle.weight = FONT_WEIGHT_BOLD;
    // strip the attribute, now that we have set it in the gfxFontStyle
    fontFace.Cut(pos, spcBold.Length());
  } else {
    aFontStyle.weight = FONT_WEIGHT_NORMAL;
  }

  // FIXME: Set aFontStyle.stretch correctly!
  aFontStyle.stretch = NS_FONT_STRETCH_NORMAL;

  // similar hopes for italic and oblique fonts...
  NS_NAMED_LITERAL_CSTRING(spcItalic, " Italic");
  NS_NAMED_LITERAL_CSTRING(spcOblique, " Oblique");
  NS_NAMED_LITERAL_CSTRING(spcObli, " Obli");
  if ((pos = fontFace.Find(spcItalic.get(), false, 0, -1)) > -1) {
    aFontStyle.style = FONT_STYLE_ITALIC;
    fontFace.Cut(pos, spcItalic.Length());
  } else if ((pos = fontFace.Find(spcOblique.get(), false, 0, -1)) > -1) {
    // oblique fonts are rare on OS/2 and not specially supported by
    // the GPI system, but at least we are trying...
    aFontStyle.style = FONT_STYLE_OBLIQUE;
    fontFace.Cut(pos, spcOblique.Length());
  } else if ((pos = fontFace.Find(spcObli.get(), false, 0, -1)) > -1) {
    // especially oblique often gets cut by the 32 char limit to "Obli",
    // so search for that, too (anything shorter would be ambiguous)
    aFontStyle.style = FONT_STYLE_OBLIQUE;
    // In this case, assume that this is the last property in the line
    // and cut off everything else, too
    // This is needed in case it was really Obliq or Obliqu...
    fontFace.Cut(pos, fontFace.Length());
  } else {
    aFontStyle.style = FONT_STYLE_NORMAL;
  }

  // just throw away any modifiers that are separated by dots (which are either
  // .Strikeout, .Underline, or .Outline, none of which have a corresponding
  // gfxFont property)
  if ((pos = fontFace.Find(".", false, 0, -1)) > -1) {
    fontFace.Cut(pos, fontFace.Length());
  }

  // seems like we need quotes around the font name
  NS_NAMED_LITERAL_STRING(quote, "\"");
  aFontName = quote + fontFace + quote;

  return true;
}
Beispiel #9
0
nsresult
PluginDocument::CreateSyntheticPluginDocument()
{
  NS_ASSERTION(!GetShell() || !GetShell()->DidInitialize(),
               "Creating synthetic plugin document content too late");

  // make our generic document
  nsresult rv = MediaDocument::CreateSyntheticDocument();
  NS_ENSURE_SUCCESS(rv, rv);
  // then attach our plugin

  Element* body = GetBodyElement();
  if (!body) {
    NS_WARNING("no body on plugin document!");
    return NS_ERROR_FAILURE;
  }

  // remove margins from body
  NS_NAMED_LITERAL_STRING(zero, "0");
  body->SetAttr(kNameSpaceID_None, nsGkAtoms::marginwidth, zero, false);
  body->SetAttr(kNameSpaceID_None, nsGkAtoms::marginheight, zero, false);


  // make plugin content
  nsRefPtr<mozilla::dom::NodeInfo> nodeInfo;
  nodeInfo = mNodeInfoManager->GetNodeInfo(nsGkAtoms::embed, nullptr,
                                           kNameSpaceID_XHTML,
                                           nsIDOMNode::ELEMENT_NODE);
  rv = NS_NewHTMLElement(getter_AddRefs(mPluginContent), nodeInfo.forget(),
                         NOT_FROM_PARSER);
  NS_ENSURE_SUCCESS(rv, rv);

  // make it a named element
  mPluginContent->SetAttr(kNameSpaceID_None, nsGkAtoms::name,
                          NS_LITERAL_STRING("plugin"), false);

  // fill viewport and auto-resize
  NS_NAMED_LITERAL_STRING(percent100, "100%");
  mPluginContent->SetAttr(kNameSpaceID_None, nsGkAtoms::width, percent100,
                          false);
  mPluginContent->SetAttr(kNameSpaceID_None, nsGkAtoms::height, percent100,
                          false);

  // set URL
  nsAutoCString src;
  mDocumentURI->GetSpec(src);
  mPluginContent->SetAttr(kNameSpaceID_None, nsGkAtoms::src,
                          NS_ConvertUTF8toUTF16(src), false);

  // set mime type
  mPluginContent->SetAttr(kNameSpaceID_None, nsGkAtoms::type,
                          NS_ConvertUTF8toUTF16(mMimeType), false);

  // nsHTML(Shared)ObjectElement does not kick off a load on BindToTree if it is
  // to a PluginDocument
  body->AppendChildTo(mPluginContent, false);

  return NS_OK;


}
Beispiel #10
0
nsresult
ShutdownXPCOM(nsIServiceManager* aServMgr)
{
  // Make sure the hang monitor is enabled for shutdown.
  HangMonitor::NotifyActivity();

  if (!NS_IsMainThread()) {
    NS_RUNTIMEABORT("Shutdown on wrong thread");
  }

  nsresult rv;
  nsCOMPtr<nsISimpleEnumerator> moduleLoaders;

  // Notify observers of xpcom shutting down
  {
    // Block it so that the COMPtr will get deleted before we hit
    // servicemanager shutdown

    nsCOMPtr<nsIThread> thread = do_GetCurrentThread();
    if (NS_WARN_IF(!thread)) {
      return NS_ERROR_UNEXPECTED;
    }

    RefPtr<nsObserverService> observerService;
    CallGetService("@mozilla.org/observer-service;1",
                   (nsObserverService**)getter_AddRefs(observerService));

    if (observerService) {
      observerService->NotifyObservers(nullptr,
                                       NS_XPCOM_WILL_SHUTDOWN_OBSERVER_ID,
                                       nullptr);

      nsCOMPtr<nsIServiceManager> mgr;
      rv = NS_GetServiceManager(getter_AddRefs(mgr));
      if (NS_SUCCEEDED(rv)) {
        observerService->NotifyObservers(mgr, NS_XPCOM_SHUTDOWN_OBSERVER_ID,
                                         nullptr);
      }
    }

    // This must happen after the shutdown of media and widgets, which
    // are triggered by the NS_XPCOM_SHUTDOWN_OBSERVER_ID notification.
    NS_ProcessPendingEvents(thread);
    gfxPlatform::ShutdownLayersIPC();

    mozilla::scache::StartupCache::DeleteSingleton();
    if (observerService)
      observerService->NotifyObservers(nullptr,
                                       NS_XPCOM_SHUTDOWN_THREADS_OBSERVER_ID,
                                       nullptr);

    gXPCOMThreadsShutDown = true;
    NS_ProcessPendingEvents(thread);

    // Shutdown the timer thread and all timers that might still be alive before
    // shutting down the component manager
    nsTimerImpl::Shutdown();

    NS_ProcessPendingEvents(thread);

    // Shutdown all remaining threads.  This method does not return until
    // all threads created using the thread manager (with the exception of
    // the main thread) have exited.
    nsThreadManager::get()->Shutdown();

    NS_ProcessPendingEvents(thread);

    HangMonitor::NotifyActivity();

    // Late-write checks needs to find the profile directory, so it has to
    // be initialized before mozilla::services::Shutdown or (because of
    // xpcshell tests replacing the service) modules being unloaded.
    mozilla::InitLateWriteChecks();

    // We save the "xpcom-shutdown-loaders" observers to notify after
    // the observerservice is gone.
    if (observerService) {
      observerService->EnumerateObservers(NS_XPCOM_SHUTDOWN_LOADERS_OBSERVER_ID,
                                          getter_AddRefs(moduleLoaders));

      observerService->Shutdown();
    }
  }

  // Free ClearOnShutdown()'ed smart pointers.  This needs to happen *after*
  // we've finished notifying observers of XPCOM shutdown, because shutdown
  // observers themselves might call ClearOnShutdown().
  mozilla::KillClearOnShutdown();

  // XPCOM is officially in shutdown mode NOW
  // Set this only after the observers have been notified as this
  // will cause servicemanager to become inaccessible.
  mozilla::services::Shutdown();

#ifdef DEBUG_dougt
  fprintf(stderr, "* * * * XPCOM shutdown. Access will be denied * * * * \n");
#endif
  // We may have AddRef'd for the caller of NS_InitXPCOM, so release it
  // here again:
  NS_IF_RELEASE(aServMgr);

  // Shutdown global servicemanager
  if (nsComponentManagerImpl::gComponentManager) {
    nsComponentManagerImpl::gComponentManager->FreeServices();
  }

  // Release the directory service
  NS_IF_RELEASE(nsDirectoryService::gService);

  free(gGREBinPath);
  gGREBinPath = nullptr;

  if (moduleLoaders) {
    bool more;
    nsCOMPtr<nsISupports> el;
    while (NS_SUCCEEDED(moduleLoaders->HasMoreElements(&more)) && more) {
      moduleLoaders->GetNext(getter_AddRefs(el));

      // Don't worry about weak-reference observers here: there is
      // no reason for weak-ref observers to register for
      // xpcom-shutdown-loaders

      // FIXME: This can cause harmless writes from sqlite committing
      // log files. We have to ignore them before we can move
      // the mozilla::PoisonWrite call before this point. See bug
      // 834945 for the details.
      nsCOMPtr<nsIObserver> obs(do_QueryInterface(el));
      if (obs) {
        obs->Observe(nullptr, NS_XPCOM_SHUTDOWN_LOADERS_OBSERVER_ID, nullptr);
      }
    }

    moduleLoaders = nullptr;
  }

  nsCycleCollector_shutdown();

  layers::AsyncTransactionTrackersHolder::Finalize();

  PROFILER_MARKER("Shutdown xpcom");
  // If we are doing any shutdown checks, poison writes.
  if (gShutdownChecks != SCM_NOTHING) {
#ifdef XP_MACOSX
    mozilla::OnlyReportDirtyWrites();
#endif /* XP_MACOSX */
    mozilla::BeginLateWriteChecks();
  }

  // Shutdown nsLocalFile string conversion
  NS_ShutdownLocalFile();
#ifdef XP_UNIX
  NS_ShutdownNativeCharsetUtils();
#endif

#if defined(XP_WIN)
  // This exit(0) call is intended to be temporary, to get shutdown leak
  // checking working on Linux.
  // On Windows XP debug, there are intermittent failures in
  // dom/media/tests/mochitest/test_peerConnection_basicH264Video.html
  // if we don't exit early in a child process. See bug 1073310.
  if (XRE_IsContentProcess() && !IsVistaOrLater()) {
      NS_WARNING("Exiting child process early!");
      exit(0);
  }
#endif

  // Shutdown xpcom. This will release all loaders and cause others holding
  // a refcount to the component manager to release it.
  if (nsComponentManagerImpl::gComponentManager) {
    rv = (nsComponentManagerImpl::gComponentManager)->Shutdown();
    NS_ASSERTION(NS_SUCCEEDED(rv), "Component Manager shutdown failed.");
  } else {
    NS_WARNING("Component Manager was never created ...");
  }

#ifdef MOZ_ENABLE_PROFILER_SPS
  // In optimized builds we don't do shutdown collections by default, so
  // uncollected (garbage) objects may keep the nsXPConnect singleton alive,
  // and its XPCJSRuntime along with it. However, we still destroy various
  // bits of state in JS_ShutDown(), so we need to make sure the profiler
  // can't access them when it shuts down. This call nulls out the
  // JS pseudo-stack's internal reference to the main thread JSRuntime,
  // duplicating the call in XPCJSRuntime::~XPCJSRuntime() in case that
  // never fired.
  if (PseudoStack* stack = mozilla_get_pseudo_stack()) {
    stack->sampleRuntime(nullptr);
  }
#endif

  // Shut down the JS engine.
  JS_ShutDown();

  // Release our own singletons
  // Do this _after_ shutting down the component manager, because the
  // JS component loader will use XPConnect to call nsIModule::canUnload,
  // and that will spin up the InterfaceInfoManager again -- bad mojo
  XPTInterfaceInfoManager::FreeInterfaceInfoManager();

  // Finally, release the component manager last because it unloads the
  // libraries:
  if (nsComponentManagerImpl::gComponentManager) {
    nsrefcnt cnt;
    NS_RELEASE2(nsComponentManagerImpl::gComponentManager, cnt);
    NS_ASSERTION(cnt == 0, "Component Manager being held past XPCOM shutdown.");
  }
  nsComponentManagerImpl::gComponentManager = nullptr;
  nsCategoryManager::Destroy();

  NS_PurgeAtomTable();

  NS_IF_RELEASE(gDebug);

  delete sIOThread;
  sIOThread = nullptr;

  delete sMessageLoop;
  sMessageLoop = nullptr;

  if (sCommandLineWasInitialized) {
    CommandLine::Terminate();
    sCommandLineWasInitialized = false;
  }

  delete sExitManager;
  sExitManager = nullptr;

  Omnijar::CleanUp();

  HangMonitor::Shutdown();

  delete sMainHangMonitor;
  sMainHangMonitor = nullptr;

  BackgroundHangMonitor::Shutdown();

  profiler_shutdown();

  NS_LogTerm();

#if defined(MOZ_WIDGET_GONK)
  // This exit(0) call is intended to be temporary, to get shutdown leak
  // checking working on Linux.
  // On debug B2G, the child process crashes very late.  Instead, just
  // give up so at least we exit cleanly. See bug 1071866.
  if (XRE_IsContentProcess()) {
      NS_WARNING("Exiting child process early!");
      exit(0);
  }
#endif

  return NS_OK;
}
TileClient
ClientTiledLayerBuffer::ValidateTile(TileClient aTile,
                                    const nsIntPoint& aTileOrigin,
                                    const nsIntRegion& aDirtyRegion)
{
  PROFILER_LABEL("ClientTiledLayerBuffer", "ValidateTile");

#ifdef GFX_TILEDLAYER_PREF_WARNINGS
  if (aDirtyRegion.IsComplex()) {
    printf_stderr("Complex region\n");
  }
#endif

  if (aTile.IsPlaceholderTile()) {
    aTile.SetLayerManager(mManager);
  }

  // Discard our front and backbuffers if our contents changed. In this case
  // the calling code will already have taken care of invalidating the entire
  // layer.
  if (HasFormatChanged()) {
    aTile.DiscardBackBuffer();
    aTile.DiscardFrontBuffer();
  }

  bool createdTextureClient = false;
  nsIntRegion offsetDirtyRegion = aDirtyRegion.MovedBy(-aTileOrigin);
  bool usingSinglePaintBuffer = !!mSinglePaintDrawTarget;
  RefPtr<TextureClient> backBuffer =
    aTile.GetBackBuffer(offsetDirtyRegion,
                        mManager->GetTexturePool(gfxPlatform::GetPlatform()->Optimal2DFormatForContent(GetContentType())),
                        &createdTextureClient, !usingSinglePaintBuffer);

  if (!backBuffer->Lock(OPEN_READ_WRITE)) {
    NS_WARNING("Failed to lock tile TextureClient for updating.");
    aTile.DiscardFrontBuffer();
    return aTile;
  }

  // We must not keep a reference to the DrawTarget after it has been unlocked,
  // make sure these are null'd before unlocking as destruction of the context
  // may cause the target to be flushed.
  RefPtr<DrawTarget> drawTarget = backBuffer->AsTextureClientDrawTarget()->GetAsDrawTarget();
  drawTarget->SetTransform(Matrix());

  RefPtr<gfxContext> ctxt = new gfxContext(drawTarget);

  if (usingSinglePaintBuffer) {
    // XXX Perhaps we should just copy the bounding rectangle here?
    RefPtr<gfx::SourceSurface> source = mSinglePaintDrawTarget->Snapshot();
    nsIntRegionRectIterator it(aDirtyRegion);
    for (const nsIntRect* dirtyRect = it.Next(); dirtyRect != nullptr; dirtyRect = it.Next()) {
#ifdef GFX_TILEDLAYER_PREF_WARNINGS
      printf_stderr(" break into subdirtyRect %i, %i, %i, %i\n",
                    dirtyRect->x, dirtyRect->y, dirtyRect->width, dirtyRect->height);
#endif
      gfx::Rect drawRect(dirtyRect->x - aTileOrigin.x,
                         dirtyRect->y - aTileOrigin.y,
                         dirtyRect->width,
                         dirtyRect->height);
      drawRect.Scale(mResolution);

      gfx::IntRect copyRect(NS_roundf((dirtyRect->x - mSinglePaintBufferOffset.x) * mResolution),
                            NS_roundf((dirtyRect->y - mSinglePaintBufferOffset.y) * mResolution),
                            drawRect.width,
                            drawRect.height);
      gfx::IntPoint copyTarget(NS_roundf(drawRect.x), NS_roundf(drawRect.y));
      drawTarget->CopySurface(source, copyRect, copyTarget);

      // Mark the newly updated area as invalid in the front buffer
      aTile.mInvalidFront.Or(aTile.mInvalidFront, nsIntRect(copyTarget.x, copyTarget.y, copyRect.width, copyRect.height));
    }

    // The new buffer is now validated, remove the dirty region from it.
    aTile.mInvalidBack.Sub(nsIntRect(0, 0, TILEDLAYERBUFFER_TILE_SIZE, TILEDLAYERBUFFER_TILE_SIZE),
                           offsetDirtyRegion);
  } else {
    // Area of the full tile...
    nsIntRegion tileRegion = nsIntRect(aTileOrigin.x, aTileOrigin.y, TILEDLAYERBUFFER_TILE_SIZE, TILEDLAYERBUFFER_TILE_SIZE);

    // Intersect this area with the portion that's dirty.
    tileRegion = tileRegion.Intersect(aDirtyRegion);

    // Move invalid areas into layer space.
    aTile.mInvalidFront.MoveBy(aTileOrigin);
    aTile.mInvalidBack.MoveBy(aTileOrigin);

    // Add the area that's going to be redrawn to the invalid area of the
    // front region.
    aTile.mInvalidFront.Or(aTile.mInvalidFront, tileRegion);

    // Add invalid areas of the backbuffer to the area to redraw.
    tileRegion.Or(tileRegion, aTile.mInvalidBack);

    // Move invalid areas back into tile space.
    aTile.mInvalidFront.MoveBy(-aTileOrigin);

    // This will be validated now.
    aTile.mInvalidBack.SetEmpty();

    nsIntRect bounds = tileRegion.GetBounds();
    bounds.ScaleRoundOut(mResolution, mResolution);
    bounds.MoveBy(-aTileOrigin);

    if (GetContentType() != gfxContentType::COLOR) {
      drawTarget->ClearRect(Rect(bounds.x, bounds.y, bounds.width, bounds.height));
    }

    ctxt->NewPath();
    ctxt->Clip(gfxRect(bounds.x, bounds.y, bounds.width, bounds.height));
    ctxt->Scale(mResolution, mResolution);
    ctxt->Translate(gfxPoint(-aTileOrigin.x, -aTileOrigin.y));
    mCallback(mThebesLayer, ctxt,
              tileRegion.GetBounds(),
              DrawRegionClip::CLIP_NONE,
              nsIntRegion(), mCallbackData);

  }

#ifdef GFX_TILEDLAYER_DEBUG_OVERLAY
  DrawDebugOverlay(drawTarget, aTileOrigin.x * mResolution,
                   aTileOrigin.y * mResolution, GetTileLength(), GetTileLength());
#endif

  ctxt = nullptr;
  drawTarget = nullptr;

  backBuffer->Unlock();

  aTile.Flip();

  if (createdTextureClient) {
    if (!mCompositableClient->AddTextureClient(backBuffer)) {
      NS_WARNING("Failed to add tile TextureClient.");
      aTile.DiscardFrontBuffer();
      aTile.DiscardBackBuffer();
      return aTile;
    }
  }

  // Note, we don't call UpdatedTexture. The Updated function is called manually
  // by the TiledContentHost before composition.

  if (backBuffer->HasInternalBuffer()) {
    // If our new buffer has an internal buffer, we don't want to keep another
    // TextureClient around unnecessarily, so discard the back-buffer.
    aTile.DiscardBackBuffer();
  }

  return aTile;
}
Beispiel #12
0
void
FileReader::ReadFileContent(Blob& aBlob,
                            const nsAString &aCharset,
                            eDataFormat aDataFormat,
                            ErrorResult& aRv)
{
    //Implicit abort to clear any other activity going on
    ErrorResult error;
    Abort(error);
    error.SuppressException();

    if (mReadyState == LOADING) {
        // A nested ReadAsSomething() as been called during one of the events
        // dispatched by Abort(). We have to terminate this operation in order to
        // continue the nested one.
        aRv.Throw(NS_ERROR_ABORT);
        return;
    }

    mError = nullptr;
    SetDOMStringToNull(mResult);
    mTransferred = 0;
    mTotal = 0;
    mReadyState = EMPTY;
    FreeFileData();

    mBlob = &aBlob;
    mDataFormat = aDataFormat;
    CopyUTF16toUTF8(aCharset, mCharset);

    nsresult rv;
    nsCOMPtr<nsIStreamTransportService> sts =
        do_GetService(kStreamTransportServiceCID, &rv);
    if (NS_WARN_IF(NS_FAILED(rv))) {
        aRv.Throw(rv);
        return;
    }

    nsCOMPtr<nsIInputStream> stream;
    mBlob->GetInternalStream(getter_AddRefs(stream), aRv);
    if (NS_WARN_IF(aRv.Failed())) {
        return;
    }

    nsCOMPtr<nsITransport> transport;
    aRv = sts->CreateInputTransport(stream,
                                    /* aStartOffset */ 0,
                                    /* aReadLimit */ -1,
                                    /* aCloseWhenDone */ true,
                                    getter_AddRefs(transport));
    if (NS_WARN_IF(aRv.Failed())) {
        return;
    }

    nsCOMPtr<nsIInputStream> wrapper;
    aRv = transport->OpenInputStream(/* aFlags */ 0,
            /* aSegmentSize */ 0,
            /* aSegmentCount */ 0,
            getter_AddRefs(wrapper));
    if (NS_WARN_IF(aRv.Failed())) {
        return;
    }

    MOZ_ASSERT(!mAsyncStream);
    mAsyncStream = do_QueryInterface(wrapper);
    MOZ_ASSERT(mAsyncStream);

    mTotal = mBlob->GetSize(aRv);
    if (NS_WARN_IF(aRv.Failed())) {
        return;
    }

    aRv = DoAsyncWait();
    if (NS_WARN_IF(aRv.Failed())) {
        return;
    }

    //FileReader should be in loading state here
    mReadyState = LOADING;
    DispatchProgressEvent(NS_LITERAL_STRING(LOADSTART_STR));

    if (mDataFormat == FILE_AS_ARRAYBUFFER) {
        mFileData = js_pod_malloc<char>(mTotal);
        if (!mFileData) {
            NS_WARNING("Preallocation failed for ReadFileData");
            aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
        }
    }
}
Beispiel #13
0
void
TextComposition::DispatchCompositionEvent(
                   WidgetCompositionEvent* aCompositionEvent,
                   nsEventStatus* aStatus,
                   EventDispatchingCallback* aCallBack,
                   bool aIsSynthesized)
{
  if (Destroyed()) {
    *aStatus = nsEventStatus_eConsumeNoDefault;
    return;
  }

  // If this instance has requested to commit or cancel composition but
  // is not synthesizing commit event, that means that the IME commits or
  // cancels the composition asynchronously.  Typically, iBus behaves so.
  // Then, synthesized events which were dispatched immediately after
  // the request has already committed our editor's composition string and
  // told it to web apps.  Therefore, we should ignore the delayed events.
  if (mRequestedToCommitOrCancel && !aIsSynthesized) {
    *aStatus = nsEventStatus_eConsumeNoDefault;
    return;
  }

  // IME may commit composition with empty string for a commit request or
  // with non-empty string for a cancel request.  We should prevent such
  // unexpected result.  E.g., web apps may be confused if they implement
  // autocomplete which attempts to commit composition forcibly when the user
  // selects one of suggestions but composition string is cleared by IME.
  // Note that most Chinese IMEs don't expose actual composition string to us.
  // They typically tell us an IDEOGRAPHIC SPACE or empty string as composition
  // string.  Therefore, we should hack it only when:
  // 1. committing string is empty string at requesting commit but the last
  //    data isn't IDEOGRAPHIC SPACE.
  // 2. non-empty string is committed at requesting cancel.
  if (!aIsSynthesized && (mIsRequestingCommit || mIsRequestingCancel)) {
    nsString* committingData = nullptr;
    switch (aCompositionEvent->message) {
      case NS_COMPOSITION_END:
      case NS_COMPOSITION_CHANGE:
        committingData = &aCompositionEvent->mData;
        break;
      default:
        NS_WARNING("Unexpected event comes during committing or "
                   "canceling composition");
        break;
    }
    if (committingData) {
      if (mIsRequestingCommit && committingData->IsEmpty() &&
          mLastData != IDEOGRAPHIC_SPACE) {
        committingData->Assign(mLastData);
      } else if (mIsRequestingCancel && !committingData->IsEmpty()) {
        committingData->Truncate();
      }
    }
  }

  if (aCompositionEvent->message == NS_COMPOSITION_CHANGE) {
    if (!MaybeDispatchCompositionUpdate(aCompositionEvent)) {
      return;
    }
  }

  EventDispatcher::Dispatch(mNode, mPresContext,
                            aCompositionEvent, nullptr, aStatus, aCallBack);

  if (NS_WARN_IF(Destroyed())) {
    return;
  }

  // Emulate editor behavior of compositionchange event (DOM text event) handler
  // if no editor handles composition events.
  if (aCompositionEvent->message == NS_COMPOSITION_CHANGE && !HasEditor()) {
    EditorWillHandleCompositionChangeEvent(aCompositionEvent);
    EditorDidHandleCompositionChangeEvent();
  }

#ifdef DEBUG
  else if (aCompositionEvent->message == NS_COMPOSITION_END) {
    MOZ_ASSERT(!mIsComposing, "Why is the editor still composing?");
    MOZ_ASSERT(!HasEditor(), "Why does the editor still keep to hold this?");
  }
#endif // #ifdef DEBUG

  // Notify composition update to widget if possible
  NotityUpdateComposition(aCompositionEvent);
}
Beispiel #14
0
void
DataTransferItem::FillInExternalData()
{
  if (mData) {
    return;
  }

  NS_ConvertUTF16toUTF8 utf8format(mType);
  const char* format = utf8format.get();
  if (strcmp(format, "text/plain") == 0) {
    format = kUnicodeMime;
  } else if (strcmp(format, "text/uri-list") == 0) {
    format = kURLDataMime;
  }

  nsCOMPtr<nsITransferable> trans =
    do_CreateInstance("@mozilla.org/widget/transferable;1");
  if (NS_WARN_IF(!trans)) {
    return;
  }

  trans->Init(nullptr);
  trans->AddDataFlavor(format);

  if (mDataTransfer->GetEventMessage() == ePaste) {
    MOZ_ASSERT(mIndex == 0, "index in clipboard must be 0");

    nsCOMPtr<nsIClipboard> clipboard =
      do_GetService("@mozilla.org/widget/clipboard;1");
    if (!clipboard || mDataTransfer->ClipboardType() < 0) {
      return;
    }

    nsresult rv = clipboard->GetData(trans, mDataTransfer->ClipboardType());
    if (NS_WARN_IF(NS_FAILED(rv))) {
      return;
    }
  } else {
    nsCOMPtr<nsIDragSession> dragSession = nsContentUtils::GetDragSession();
    if (!dragSession) {
      return;
    }

    nsresult rv = dragSession->GetData(trans, mIndex);
    if (NS_WARN_IF(NS_FAILED(rv))) {
      return;
    }
  }

  uint32_t length = 0;
  nsCOMPtr<nsISupports> data;
  nsresult rv = trans->GetTransferData(format, getter_AddRefs(data), &length);
  if (NS_WARN_IF(NS_FAILED(rv) || !data)) {
    return;
  }

  // Fill the variant
  RefPtr<nsVariantCC> variant = new nsVariantCC();

  eKind oldKind = Kind();
  if (oldKind == KIND_FILE) {
    // Because this is an external piece of data, mType is one of kFileMime,
    // kPNGImageMime, kJPEGImageMime, or kGIFImageMime. Some of these types
    // are passed in as a nsIInputStream which must be converted to a
    // dom::File before storing.
    if (nsCOMPtr<nsIInputStream> istream = do_QueryInterface(data)) {
      RefPtr<File> file = CreateFileFromInputStream(istream);
      if (NS_WARN_IF(!file)) {
        return;
      }
      data = do_QueryObject(file);
    }

    variant->SetAsISupports(data);
  } else {
    // We have an external piece of string data. Extract it and store it in the variant
    MOZ_ASSERT(oldKind == KIND_STRING);

    nsCOMPtr<nsISupportsString> supportsstr = do_QueryInterface(data);
    if (supportsstr) {
      nsAutoString str;
      supportsstr->GetData(str);
      variant->SetAsAString(str);
    } else {
      nsCOMPtr<nsISupportsCString> supportscstr = do_QueryInterface(data);
      if (supportscstr) {
        nsAutoCString str;
        supportscstr->GetData(str);
        variant->SetAsACString(str);
      }
    }
  }

  SetData(variant);

  if (oldKind != Kind()) {
    NS_WARNING("Clipboard data provided by the OS does not match predicted kind");
    mDataTransfer->TypesListMayHaveChanged();
  }
}
Beispiel #15
0
nsresult nsAutoConfig::downloadAutoConfig()
{
    nsresult rv;
    nsAutoCString emailAddr;
    nsXPIDLCString urlName;
    static bool firstTime = true;
    
    if (mConfigURL.IsEmpty()) {
        PR_LOG(MCD, PR_LOG_DEBUG, ("global config url is empty - did you set autoadmin.global_config_url?\n"));
        NS_WARNING("AutoConfig called without global_config_url");
        return NS_OK;
    }
    
    // If there is an email address appended as an argument to the ConfigURL
    // in the previous read, we need to remove it when timer kicks in and 
    // downloads the autoconfig file again. 
    // If necessary, the email address will be added again as an argument.
    int32_t index = mConfigURL.RFindChar((char16_t)'?');
    if (index != -1)
        mConfigURL.Truncate(index);

    // Clean up the previous read, the new read is going to use the same buffer
    if (!mBuf.IsEmpty())
        mBuf.Truncate(0);

    // Get the preferences branch and save it to the member variable
    if (!mPrefBranch) {
        nsCOMPtr<nsIPrefService> prefs =
            do_GetService(NS_PREFSERVICE_CONTRACTID, &rv);
        if (NS_FAILED(rv)) 
            return rv;
    
        rv = prefs->GetBranch(nullptr,getter_AddRefs(mPrefBranch));
        if (NS_FAILED(rv))
            return rv;
    }
    
    // Check to see if the network is online/offline 
    nsCOMPtr<nsIIOService> ios = do_GetService(NS_IOSERVICE_CONTRACTID, &rv);
    if (NS_FAILED(rv)) 
        return rv;
    
    bool offline;
    rv = ios->GetOffline(&offline);
    if (NS_FAILED(rv)) 
        return rv;
    
    if (offline) {
        bool offlineFailover;
        rv = mPrefBranch->GetBoolPref("autoadmin.offline_failover", 
                                      &offlineFailover);
        // Read the failover.jsc if the network is offline and the pref says so
        if (NS_SUCCEEDED(rv) && offlineFailover)
            return readOfflineFile();
    }

    /* Append user's identity at the end of the URL if the pref says so.
       First we are checking for the user's email address but if it is not
       available in the case where the client is used without messenger, user's
       profile name will be used as an unique identifier
    */
    bool appendMail;
    rv = mPrefBranch->GetBoolPref("autoadmin.append_emailaddr", &appendMail);
    if (NS_SUCCEEDED(rv) && appendMail) {
        rv = getEmailAddr(emailAddr);
        if (NS_SUCCEEDED(rv) && emailAddr.get()) {
            /* Adding the unique identifier at the end of autoconfig URL. 
               In this case the autoconfig URL is a script and 
               emailAddr as passed as an argument 
            */
            mConfigURL.Append('?');
            mConfigURL.Append(emailAddr); 
        }
    }
    
    // create a new url 
    nsCOMPtr<nsIURI> url;
    nsCOMPtr<nsIChannel> channel;
    
    rv = NS_NewURI(getter_AddRefs(url), mConfigURL.get(), nullptr, nullptr);
    if (NS_FAILED(rv))
    {
        PR_LOG(MCD, PR_LOG_DEBUG, ("failed to create URL - is autoadmin.global_config_url valid? - %s\n", mConfigURL.get()));
        return rv;
    }

    PR_LOG(MCD, PR_LOG_DEBUG, ("running MCD url %s\n", mConfigURL.get()));
    // open a channel for the url
    rv = NS_NewChannel(getter_AddRefs(channel),
                       url,
                       nsContentUtils::GetSystemPrincipal(),
                       nsILoadInfo::SEC_NORMAL,
                       nsIContentPolicy::TYPE_OTHER,
                       nullptr,  // loadGroup
                       nullptr,  // aCallbacks
                       nsIRequest::INHIBIT_PERSISTENT_CACHING |
                       nsIRequest::LOAD_BYPASS_CACHE);

    if (NS_FAILED(rv)) 
        return rv;

    rv = channel->AsyncOpen(this, nullptr); 
    if (NS_FAILED(rv)) {
        readOfflineFile();
        return rv;
    }
    
    // Set a repeating timer if the pref is set.
    // This is to be done only once.
    // Also We are having the event queue processing only for the startup
    // It is not needed with the repeating timer.
    if (firstTime) {
        firstTime = false;
    
        // Getting the current thread. If we start an AsyncOpen, the thread
        // needs to wait before the reading of autoconfig is done

        nsCOMPtr<nsIThread> thread = do_GetCurrentThread();
        NS_ENSURE_STATE(thread);
    
        /* process events until we're finished. AutoConfig.jsc reading needs
           to be finished before the browser starts loading up
           We are waiting for the mLoaded which will be set through 
           onStopRequest or readOfflineFile methods
           There is a possibility of deadlock so we need to make sure
           that mLoaded will be set to true in any case (success/failure)
        */
        
        while (!mLoaded)
            NS_ENSURE_STATE(NS_ProcessNextEvent(thread));
        
        int32_t minutes;
        rv = mPrefBranch->GetIntPref("autoadmin.refresh_interval", 
                                     &minutes);
        if (NS_SUCCEEDED(rv) && minutes > 0) {
            // Create a new timer and pass this nsAutoConfig 
            // object as a timer callback. 
            mTimer = do_CreateInstance("@mozilla.org/timer;1",&rv);
            if (NS_FAILED(rv)) 
                return rv;
            rv = mTimer->InitWithCallback(this, minutes * 60 * 1000, 
                             nsITimer::TYPE_REPEATING_SLACK);
            if (NS_FAILED(rv)) 
                return rv;
        }
    } //first_time
    
    return NS_OK;
} // nsPref::downloadAutoConfig()
void
UnixSocketImpl::OnFileCanReadWithoutBlocking(int aFd)
{
  MOZ_ASSERT(!NS_IsMainThread());
  MOZ_ASSERT(!mShuttingDownOnIOThread);

  SocketConnectionStatus status = mConsumer->GetConnectionStatus();
  if (status == SOCKET_CONNECTED) {
    // Read all of the incoming data.
    while (true) {
      uint8_t data[MAX_READ_SIZE];
      ssize_t ret = read(aFd, data, MAX_READ_SIZE);
      if (ret <= 0) {
        if (ret == -1) {
          if (errno == EINTR) {
            continue; // retry system call when interrupted
          }
          if (errno == EAGAIN || errno == EWOULDBLOCK) {
            return; // no data available: return and re-poll
          }

#ifdef DEBUG
          NS_WARNING("Cannot read from network");
#endif
          // else fall through to error handling on other errno's
        }

        // We're done with our descriptors. Ensure that spurious events don't
        // cause us to end up back here.
        mReadWatcher.StopWatchingFileDescriptor();
        mWriteWatcher.StopWatchingFileDescriptor();
        nsRefPtr<RequestClosingSocketTask> t = new RequestClosingSocketTask(this);
        NS_DispatchToMainThread(t);
        return;
      }

      UnixSocketRawData* incoming = new UnixSocketRawData(ret);
      memcpy(incoming->mData, data, ret);
      nsRefPtr<SocketReceiveTask> t = new SocketReceiveTask(this, incoming);
      NS_DispatchToMainThread(t);

      // If ret is less than MAX_READ_SIZE, there's no more data in the socket
      // for us to read now.
      if (ret < ssize_t(MAX_READ_SIZE)) {
        return;
      }
    }

    MOZ_NOT_REACHED("We returned early");
  }

  if (status == SOCKET_LISTENING) {
    int client_fd = accept(mFd.get(), (struct sockaddr*)&mAddr, &mAddrSize);

    if (client_fd < 0) {
      return;
    }

    if (!mConnector->SetUp(client_fd)) {
      NS_WARNING("Could not set up socket!");
      return;
    }

    mReadWatcher.StopWatchingFileDescriptor();
    mWriteWatcher.StopWatchingFileDescriptor();

    mFd.reset(client_fd);
    if (!SetSocketFlags()) {
      return;
    }

    mIOLoop = nullptr;

    nsRefPtr<OnSocketEventTask> t =
      new OnSocketEventTask(this, OnSocketEventTask::CONNECT_SUCCESS);
    NS_DispatchToMainThread(t);

    SetUpIO();
  }
}
Beispiel #17
0
NS_IMETHODIMP
nsAppStartup::Quit(PRUint32 aMode)
{
  PRUint32 ferocity = (aMode & 0xF);

  // Quit the application. We will asynchronously call the appshell's
  // Exit() method via nsAppExitEvent to allow one last pass
  // through any events in the queue. This guarantees a tidy cleanup.
  nsresult rv = NS_OK;
  PRBool postedExitEvent = PR_FALSE;

  if (mShuttingDown)
    return NS_OK;

  // If we're considering quitting, we will only do so if:
  if (ferocity == eConsiderQuit) {
    if (mConsiderQuitStopper == 0) {
      // there are no windows...
      ferocity = eAttemptQuit;
    }
#ifdef XP_MACOSX
    else if (mConsiderQuitStopper == 1) {
      // ... or there is only a hiddenWindow left, and it's useless:
      nsCOMPtr<nsIAppShellService> appShell
        (do_GetService(NS_APPSHELLSERVICE_CONTRACTID));

      // Failure shouldn't be fatal, but will abort quit attempt:
      if (!appShell)
        return NS_OK;

      PRBool usefulHiddenWindow;
      appShell->GetApplicationProvidedHiddenWindow(&usefulHiddenWindow);
      nsCOMPtr<nsIXULWindow> hiddenWindow;
      appShell->GetHiddenWindow(getter_AddRefs(hiddenWindow));
      // If the one window is useful, we won't quit:
      if (!hiddenWindow || usefulHiddenWindow)
        return NS_OK;

      ferocity = eAttemptQuit;
    }
#endif
  }

  nsCOMPtr<nsIObserverService> obsService;
  if (ferocity == eAttemptQuit || ferocity == eForceQuit) {

    nsCOMPtr<nsISimpleEnumerator> windowEnumerator;
    nsCOMPtr<nsIWindowMediator> mediator (do_GetService(NS_WINDOWMEDIATOR_CONTRACTID));
    if (mediator) {
      mediator->GetEnumerator(nsnull, getter_AddRefs(windowEnumerator));
      if (windowEnumerator) {
        PRBool more;
        while (windowEnumerator->HasMoreElements(&more), more) {
          nsCOMPtr<nsISupports> window;
          windowEnumerator->GetNext(getter_AddRefs(window));
          nsCOMPtr<nsPIDOMWindow> domWindow(do_QueryInterface(window));
          if (domWindow) {
            if (!domWindow->CanClose())
              return NS_OK;
          }
        }
      }
    }

    mShuttingDown = PR_TRUE;
    if (!mRestart) {
      mRestart = (aMode & eRestart) != 0;
      gRestartMode = (aMode & 0xF0);
    }

    if (mRestart) {
      // Firefox-restarts reuse the process. Process start-time isn't a useful indicator of startup time
      PR_SetEnv(PR_smprintf("MOZ_APP_RESTART=%lld", (PRInt64) PR_Now() / PR_USEC_PER_MSEC));
    }

    obsService = mozilla::services::GetObserverService();

    if (!mAttemptingQuit) {
      mAttemptingQuit = PR_TRUE;
#ifdef XP_MACOSX
      // now even the Mac wants to quit when the last window is closed
      ExitLastWindowClosingSurvivalArea();
#endif
      if (obsService)
        obsService->NotifyObservers(nsnull, "quit-application-granted", nsnull);
    }

    /* Enumerate through each open window and close it. It's important to do
       this before we forcequit because this can control whether we really quit
       at all. e.g. if one of these windows has an unload handler that
       opens a new window. Ugh. I know. */
    CloseAllWindows();

    if (mediator) {
      if (ferocity == eAttemptQuit) {
        ferocity = eForceQuit; // assume success

        /* Were we able to immediately close all windows? if not, eAttemptQuit
           failed. This could happen for a variety of reasons; in fact it's
           very likely. Perhaps we're being called from JS and the window->Close
           method hasn't had a chance to wrap itself up yet. So give up.
           We'll return (with eConsiderQuit) as the remaining windows are
           closed. */
        mediator->GetEnumerator(nsnull, getter_AddRefs(windowEnumerator));
        if (windowEnumerator) {
          PRBool more;
          while (windowEnumerator->HasMoreElements(&more), more) {
            /* we can't quit immediately. we'll try again as the last window
               finally closes. */
            ferocity = eAttemptQuit;
            nsCOMPtr<nsISupports> window;
            windowEnumerator->GetNext(getter_AddRefs(window));
            nsCOMPtr<nsIDOMWindowInternal> domWindow(do_QueryInterface(window));
            if (domWindow) {
              PRBool closed = PR_FALSE;
              domWindow->GetClosed(&closed);
              if (!closed) {
                rv = NS_ERROR_FAILURE;
                break;
              }
            }
          }
        }
      }
    }
  }

  if (ferocity == eForceQuit) {
    // do it!

    // No chance of the shutdown being cancelled from here on; tell people
    // we're shutting down for sure while all services are still available.
    if (obsService) {
      NS_NAMED_LITERAL_STRING(shutdownStr, "shutdown");
      NS_NAMED_LITERAL_STRING(restartStr, "restart");
      obsService->NotifyObservers(nsnull, "quit-application",
        mRestart ? restartStr.get() : shutdownStr.get());
    }

    if (!mRunning) {
      postedExitEvent = PR_TRUE;
    }
    else {
      // no matter what, make sure we send the exit event.  If
      // worst comes to worst, we'll do a leaky shutdown but we WILL
      // shut down. Well, assuming that all *this* stuff works ;-).
      nsCOMPtr<nsIRunnable> event = new nsAppExitEvent(this);
      rv = NS_DispatchToCurrentThread(event);
      if (NS_SUCCEEDED(rv)) {
        postedExitEvent = PR_TRUE;
      }
      else {
        NS_WARNING("failed to dispatch nsAppExitEvent");
      }
    }
  }

  // turn off the reentrancy check flag, but not if we have
  // more asynchronous work to do still.
  if (!postedExitEvent)
    mShuttingDown = PR_FALSE;
  return rv;
}
Beispiel #18
0
void
APZEventState::ProcessTouchEvent(const WidgetTouchEvent& aEvent,
                                 const ScrollableLayerGuid& aGuid,
                                 uint64_t aInputBlockId,
                                 nsEventStatus aApzResponse,
                                 nsEventStatus aContentResponse)
{
  if (aEvent.mMessage == eTouchStart && aEvent.mTouches.Length() > 0) {
    mActiveElementManager->SetTargetElement(aEvent.mTouches[0]->GetTarget());
  }

  bool isTouchPrevented = aContentResponse == nsEventStatus_eConsumeNoDefault;
  bool sentContentResponse = false;
  APZES_LOG("Handling event type %d\n", aEvent.mMessage);
  switch (aEvent.mMessage) {
  case eTouchStart: {
    mTouchEndCancelled = false;
    sentContentResponse = SendPendingTouchPreventedResponse(false);
    // sentContentResponse can be true here if we get two TOUCH_STARTs in a row
    // and just responded to the first one.
    if (!aEvent.mFlags.mHandledByAPZ) {
      // This condition being true means this touchstart is synthetic and is
      // coming from TabParent.injectTouchEvent.
      // Since APZ doesn't know about it we don't want to send a response for
      // this block; we want to just skip over it from the point of view of
      // prevent-default notifications.
      APZES_LOG("Got a synthetic touch-start!\n");
      break;
    }
    if (isTouchPrevented) {
      mContentReceivedInputBlockCallback(aGuid, aInputBlockId, isTouchPrevented);
      sentContentResponse = true;
    } else {
      APZES_LOG("Event not prevented; pending response for %" PRIu64 " %s\n",
        aInputBlockId, Stringify(aGuid).c_str());
      mPendingTouchPreventedResponse = true;
      mPendingTouchPreventedGuid = aGuid;
      mPendingTouchPreventedBlockId = aInputBlockId;
    }
    break;
  }

  case eTouchEnd:
    if (isTouchPrevented) {
      mTouchEndCancelled = true;
      mEndTouchIsClick = false;
    }
    MOZ_FALLTHROUGH;
  case eTouchCancel:
    mActiveElementManager->HandleTouchEndEvent(mEndTouchIsClick);
    MOZ_FALLTHROUGH;
  case eTouchMove: {
    if (mPendingTouchPreventedResponse) {
      MOZ_ASSERT(aGuid == mPendingTouchPreventedGuid);
    }
    sentContentResponse = SendPendingTouchPreventedResponse(isTouchPrevented);
    break;
  }

  default:
    NS_WARNING("Unknown touch event type");
  }

  if (sentContentResponse &&
        aApzResponse == nsEventStatus_eConsumeDoDefault &&
        gfxPrefs::PointerEventsEnabled()) {
    WidgetTouchEvent cancelEvent(aEvent);
    cancelEvent.mMessage = eTouchCancel;
    cancelEvent.mFlags.mCancelable = false; // mMessage != eTouchCancel;
    for (uint32_t i = 0; i < cancelEvent.mTouches.Length(); ++i) {
      if (mozilla::dom::Touch* touch = cancelEvent.mTouches[i]) {
        touch->convertToPointer = true;
      }
    }
    nsEventStatus status;
    cancelEvent.widget->DispatchEvent(&cancelEvent, status);
  }
}
nsresult
nsFolderCompactState::FinishCompact()
{
  NS_ENSURE_TRUE(m_folder, NS_ERROR_NOT_INITIALIZED);
  NS_ENSURE_TRUE(m_file, NS_ERROR_NOT_INITIALIZED);

  // All okay time to finish up the compact process
  nsCOMPtr<nsIFile> path;
  nsCOMPtr<nsIDBFolderInfo> folderInfo;

  // get leaf name and database name of the folder
  nsresult rv = m_folder->GetFilePath(getter_AddRefs(path));
  nsCOMPtr <nsIFile> folderPath = do_CreateInstance(NS_LOCAL_FILE_CONTRACTID, &rv);
  NS_ENSURE_SUCCESS(rv, rv);
  rv = folderPath->InitWithFile(path);
  NS_ENSURE_SUCCESS(rv, rv);
  // need to make sure we put the .msf file in the same directory
  // as the original mailbox, so resolve symlinks.
  folderPath->SetFollowLinks(true);

  nsCOMPtr <nsIFile> oldSummaryFile;
  rv = GetSummaryFileLocation(folderPath, getter_AddRefs(oldSummaryFile));
  NS_ENSURE_SUCCESS(rv, rv);
  nsAutoCString dbName;
  oldSummaryFile->GetNativeLeafName(dbName);
  nsAutoCString folderName;
  path->GetNativeLeafName(folderName);

  // close down the temp file stream; preparing for deleting the old folder
  // and its database; then rename the temp folder and database
  if (m_fileStream)
  {
    m_fileStream->Flush();
    m_fileStream->Close();
    m_fileStream = nullptr;
  }

  // make sure the new database is valid.
  // Close it so we can rename the .msf file.
  if (m_db)
  {
    m_db->ForceClosed();
    m_db = nullptr;
  }

  nsCOMPtr <nsIFile> newSummaryFile;
  rv = GetSummaryFileLocation(m_file, getter_AddRefs(newSummaryFile));
  NS_ENSURE_SUCCESS(rv, rv);

  nsCOMPtr <nsIDBFolderInfo> transferInfo;
  m_folder->GetDBTransferInfo(getter_AddRefs(transferInfo));

  // close down database of the original folder
  m_folder->ForceDBClosed();

  nsCOMPtr<nsIFile> cloneFile;
  int64_t fileSize;
  rv = m_file->Clone(getter_AddRefs(cloneFile));
  if (NS_SUCCEEDED(rv))
    rv = cloneFile->GetFileSize(&fileSize);
  bool tempFileRightSize = ((uint64_t)fileSize == m_totalMsgSize);
  NS_WARN_IF_FALSE(tempFileRightSize, "temp file not of expected size in compact");

  bool folderRenameSucceeded = false;
  bool msfRenameSucceeded = false;
  if (NS_SUCCEEDED(rv) && tempFileRightSize)
  {
    // First we're going to try and move the old summary file out the way.
    // We don't delete it yet, as we want to keep the files in sync.
    nsCOMPtr<nsIFile> tempSummaryFile;
    rv = oldSummaryFile->Clone(getter_AddRefs(tempSummaryFile));
    if (NS_SUCCEEDED(rv))
      rv = tempSummaryFile->CreateUnique(nsIFile::NORMAL_FILE_TYPE, 0600);

    nsAutoCString tempSummaryFileName;
    if (NS_SUCCEEDED(rv))
      rv = tempSummaryFile->GetNativeLeafName(tempSummaryFileName);

    if (NS_SUCCEEDED(rv))
      rv = oldSummaryFile->MoveToNative((nsIFile*) nullptr, tempSummaryFileName);

    NS_WARN_IF_FALSE(NS_SUCCEEDED(rv), "error moving compacted folder's db out of the way");
    if (NS_SUCCEEDED(rv))
    {
      // Now we've successfully moved the summary file out the way, try moving
      // the newly compacted message file over the old one.
      rv = m_file->MoveToNative((nsIFile *) nullptr, folderName);
      folderRenameSucceeded = NS_SUCCEEDED(rv);
      NS_WARN_IF_FALSE(folderRenameSucceeded, "error renaming compacted folder");
      if (folderRenameSucceeded)
      {
        // That worked, so land the new summary file in the right place.
        nsCOMPtr<nsIFile> renamedCompactedSummaryFile;
        newSummaryFile->Clone(getter_AddRefs(renamedCompactedSummaryFile));
        if (renamedCompactedSummaryFile)
        {
          rv = renamedCompactedSummaryFile->MoveToNative((nsIFile *) nullptr, dbName);
          msfRenameSucceeded = NS_SUCCEEDED(rv);
        }
        NS_WARN_IF_FALSE(msfRenameSucceeded, "error renaming compacted folder's db");
      }

      if (!msfRenameSucceeded)
      {
        // Do our best to put the summary file back to where it was
        rv = tempSummaryFile->MoveToNative((nsIFile*) nullptr, dbName);
        if (NS_SUCCEEDED(rv))
          tempSummaryFile = nullptr; // flagging that a renamed db no longer exists
        else
          NS_WARNING("error restoring uncompacted folder's db");
      }
    }
    // We don't want any temporarily renamed summary file to lie around
    if (tempSummaryFile)
      tempSummaryFile->Remove(false);
  }

  NS_WARN_IF_FALSE(msfRenameSucceeded, "compact failed");
  nsresult rvReleaseFolderLock = ReleaseFolderLock();
  NS_WARN_IF_FALSE(NS_SUCCEEDED(rvReleaseFolderLock),"folder lock not released successfully");
  rv = NS_FAILED(rv) ? rv : rvReleaseFolderLock;

  // Cleanup of nstmp-named compacted files if failure
  if (!folderRenameSucceeded)
  {
    // remove the abandoned compacted version with the wrong name
    m_file->Remove(false);
  }
  if (!msfRenameSucceeded)
  {
    // remove the abandoned compacted summary file
    newSummaryFile->Remove(false);
  }

  if (msfRenameSucceeded)
  {
    // Transfer local db information from transferInfo
    nsCOMPtr<nsIMsgDBService> msgDBService =
      do_GetService(NS_MSGDB_SERVICE_CONTRACTID, &rv);
    NS_ENSURE_SUCCESS(rv, rv);
    rv = msgDBService->OpenFolderDB(m_folder, true, getter_AddRefs(m_db));
    NS_ENSURE_TRUE(m_db, NS_FAILED(rv) ? rv : NS_ERROR_FAILURE);
    // These errors are expected.
    rv = (rv == NS_MSG_ERROR_FOLDER_SUMMARY_MISSING ||
          rv == NS_MSG_ERROR_FOLDER_SUMMARY_OUT_OF_DATE) ? NS_OK : rv;
    m_db->SetSummaryValid(true);
    m_folder->SetDBTransferInfo(transferInfo);

    // since we're transferring info from the old db, we need to reset the expunged bytes
    nsCOMPtr<nsIDBFolderInfo> dbFolderInfo;
    m_db->GetDBFolderInfo(getter_AddRefs(dbFolderInfo));
    if(dbFolderInfo)
      dbFolderInfo->SetExpungedBytes(0);
  }
  if (m_db)
    m_db->Close(true);
  m_db = nullptr;

  // Notify that compaction of the folder is completed.
  nsCOMPtr<nsIMsgFolderNotificationService>
    notifier(do_GetService(NS_MSGNOTIFICATIONSERVICE_CONTRACTID));
  if (notifier)
    notifier->NotifyItemEvent(m_folder,
                              NS_LITERAL_CSTRING("FolderCompactFinish"),
                              nullptr);
  m_folder->NotifyCompactCompleted();

  if (m_compactAll)
    rv = CompactNextFolder();
  else
    CompactCompleted(rv);
      
  return rv;
}
bool
TextureImageTextureSourceOGL::Update(gfx::DataSourceSurface* aSurface,
                                     nsIntRegion* aDestRegion,
                                     gfx::IntPoint* aSrcOffset)
{
  GLContext *gl = mCompositor->gl();
  MOZ_ASSERT(gl);
  if (!gl) {
    NS_WARNING("trying to update TextureImageTextureSourceOGL without a GLContext");
    return false;
  }
  if (!aSurface) {
    gfxCriticalError() << "Invalid surface for OGL update";
    return false;
  }
  MOZ_ASSERT(aSurface);

  IntSize size = aSurface->GetSize();
  if (!mTexImage ||
      (mTexImage->GetSize() != size && !aSrcOffset) ||
      mTexImage->GetContentType() != gfx::ContentForFormat(aSurface->GetFormat())) {
    if (mFlags & TextureFlags::DISALLOW_BIGIMAGE) {
      GLint maxTextureSize;
      gl->fGetIntegerv(LOCAL_GL_MAX_TEXTURE_SIZE, &maxTextureSize);
      if (size.width > maxTextureSize || size.height > maxTextureSize) {
        NS_WARNING("Texture exceeds maximum texture size, refusing upload");
        return false;
      }
      // Explicitly use CreateBasicTextureImage instead of CreateTextureImage,
      // because CreateTextureImage might still choose to create a tiled
      // texture image.
      mTexImage = CreateBasicTextureImage(gl, size,
                                          gfx::ContentForFormat(aSurface->GetFormat()),
                                          LOCAL_GL_CLAMP_TO_EDGE,
                                          FlagsToGLFlags(mFlags));
    } else {
      // XXX - clarify which size we want to use. IncrementalContentHost will
      // require the size of the destination surface to be different from
      // the size of aSurface.
      // See bug 893300 (tracks the implementation of ContentHost for new textures).
      mTexImage = CreateTextureImage(gl,
                                     size,
                                     gfx::ContentForFormat(aSurface->GetFormat()),
                                     LOCAL_GL_CLAMP_TO_EDGE,
                                     FlagsToGLFlags(mFlags),
                                     SurfaceFormatToImageFormat(aSurface->GetFormat()));
    }
    ClearCachedFilter();

    if (aDestRegion &&
        !aSrcOffset &&
        !aDestRegion->IsEqual(gfx::IntRect(0, 0, size.width, size.height))) {
      // UpdateFromDataSource will ignore our specified aDestRegion since the texture
      // hasn't been allocated with glTexImage2D yet. Call Resize() to force the
      // allocation (full size, but no upload), and then we'll only upload the pixels
      // we care about below.
      mTexImage->Resize(size);
    }
  }

  mTexImage->UpdateFromDataSource(aSurface, aDestRegion, aSrcOffset);

  if (mTexImage->InUpdate()) {
    mTexImage->EndUpdate();
  }
  return true;
}
Beispiel #21
0
void
AudioSink::AudioLoop()
{
    AssertOnAudioThread();
    SINK_LOG("AudioLoop started");

    if (NS_FAILED(InitializeAudioStream())) {
        NS_WARNING("Initializing AudioStream failed.");
        ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
        mStateMachine->OnAudioSinkError();
        return;
    }

    while (1) {
        {
            ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
            WaitForAudioToPlay();
            if (!IsPlaybackContinuing()) {
                break;
            }
        }
        // See if there's a gap in the audio. If there is, push silence into the
        // audio hardware, so we can play across the gap.
        // Calculate the timestamp of the next chunk of audio in numbers of
        // samples.
        NS_ASSERTION(AudioQueue().GetSize() > 0, "Should have data to play");
        CheckedInt64 sampleTime = UsecsToFrames(AudioQueue().PeekFront()->mTime, mInfo.mRate);

        // Calculate the number of frames that have been pushed onto the audio hardware.
        CheckedInt64 playedFrames = UsecsToFrames(mStartTime, mInfo.mRate) + mWritten;

        CheckedInt64 missingFrames = sampleTime - playedFrames;
        if (!missingFrames.isValid() || !sampleTime.isValid()) {
            NS_WARNING("Int overflow adding in AudioLoop");
            break;
        }

        if (missingFrames.value() > AUDIO_FUZZ_FRAMES) {
            // The next audio chunk begins some time after the end of the last chunk
            // we pushed to the audio hardware. We must push silence into the audio
            // hardware so that the next audio chunk begins playback at the correct
            // time.
            missingFrames = std::min<int64_t>(UINT32_MAX, missingFrames.value());
            mWritten += PlaySilence(static_cast<uint32_t>(missingFrames.value()));
        } else {
            mWritten += PlayFromAudioQueue();
        }
        int64_t endTime = GetEndTime();
        if (endTime != -1) {
            mStateMachine->OnAudioEndTimeUpdate(endTime);
        }
    }
    ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
    MOZ_ASSERT(mStopAudioThread || AudioQueue().AtEndOfStream());
    if (!mStopAudioThread && mPlaying) {
        Drain();
    }
    SINK_LOG("AudioLoop complete");
    Cleanup();
    SINK_LOG("AudioLoop exit");
}
/*
 * Add external H.264 video codec.
 */
MediaConduitErrorCode
MediaPipelineFactory::EnsureExternalCodec(VideoSessionConduit& aConduit,
                                          VideoCodecConfig* aConfig,
                                          bool aIsSend)
{
  if (aConfig->mName == "VP8") {
#ifdef MOZ_WEBRTC_MEDIACODEC
     if (aIsSend) {
#ifdef MOZILLA_INTERNAL_API
       bool enabled = mozilla::Preferences::GetBool("media.navigator.hardware.vp8_encode.acceleration_enabled", false);
#else
       bool enabled = false;
#endif
       if (enabled) {
         nsCOMPtr<nsIGfxInfo> gfxInfo = do_GetService("@mozilla.org/gfx/info;1");
         if (gfxInfo) {
           int32_t status;
           if (NS_SUCCEEDED(gfxInfo->GetFeatureStatus(nsIGfxInfo::FEATURE_WEBRTC_HW_ACCELERATION_ENCODE, &status))) {
             if (status != nsIGfxInfo::FEATURE_STATUS_OK) {
               NS_WARNING("VP8 encoder hardware is not whitelisted: disabling.\n");
             } else {
               VideoEncoder* encoder = nullptr;
               encoder = MediaCodecVideoCodec::CreateEncoder(MediaCodecVideoCodec::CodecType::CODEC_VP8);
               if (encoder) {
                 return aConduit.SetExternalSendCodec(aConfig, encoder);
               } else {
                 return kMediaConduitNoError;
               }
             }
           }
         }
       }
     } else {
#ifdef MOZILLA_INTERNAL_API
       bool enabled = mozilla::Preferences::GetBool("media.navigator.hardware.vp8_decode.acceleration_enabled", false);
#else
       bool enabled = false;
#endif
       if (enabled) {
         nsCOMPtr<nsIGfxInfo> gfxInfo = do_GetService("@mozilla.org/gfx/info;1");
         if (gfxInfo) {
           int32_t status;
           if (NS_SUCCEEDED(gfxInfo->GetFeatureStatus(nsIGfxInfo::FEATURE_WEBRTC_HW_ACCELERATION_DECODE, &status))) {
             if (status != nsIGfxInfo::FEATURE_STATUS_OK) {
               NS_WARNING("VP8 decoder hardware is not whitelisted: disabling.\n");
             } else {
               VideoDecoder* decoder;
               decoder = MediaCodecVideoCodec::CreateDecoder(MediaCodecVideoCodec::CodecType::CODEC_VP8);
               if (decoder) {
                 return aConduit.SetExternalRecvCodec(aConfig, decoder);
               } else {
                 return kMediaConduitNoError;
               }
             }
           }
         }
       }
     }
#endif
     return kMediaConduitNoError;
  } else if (aConfig->mName == "VP9") {
    return kMediaConduitNoError;
  } else if (aConfig->mName == "H264") {
    if (aConduit.CodecPluginID() != 0) {
      return kMediaConduitNoError;
    }
    // Register H.264 codec.
    if (aIsSend) {
      VideoEncoder* encoder = nullptr;
#ifdef MOZ_WEBRTC_OMX
      encoder =
          OMXVideoCodec::CreateEncoder(OMXVideoCodec::CodecType::CODEC_H264);
#else
      encoder = GmpVideoCodec::CreateEncoder();
#endif
      if (encoder) {
        return aConduit.SetExternalSendCodec(aConfig, encoder);
      } else {
        return kMediaConduitInvalidSendCodec;
      }
    } else {
      VideoDecoder* decoder = nullptr;
#ifdef MOZ_WEBRTC_OMX
      decoder =
          OMXVideoCodec::CreateDecoder(OMXVideoCodec::CodecType::CODEC_H264);
#else
      decoder = GmpVideoCodec::CreateDecoder();
#endif
      if (decoder) {
        return aConduit.SetExternalRecvCodec(aConfig, decoder);
      } else {
        return kMediaConduitInvalidReceiveCodec;
      }
    }
    NS_NOTREACHED("Shouldn't get here!");
  } else {
    MOZ_MTLOG(ML_ERROR,
              "Invalid video codec configured: " << aConfig->mName.c_str());
    return aIsSend ? kMediaConduitInvalidSendCodec
                   : kMediaConduitInvalidReceiveCodec;
  }

  NS_NOTREACHED("Shouldn't get here!");
}
NS_IMETHODIMP
nsHTTPCompressConv::OnDataAvailable(nsIRequest* request,
                                    nsISupports *aContext,
                                    nsIInputStream *iStr,
                                    PRUint32 aSourceOffset,
                                    PRUint32 aCount)
{
    nsresult rv = NS_ERROR_INVALID_CONTENT_ENCODING;
    PRUint32 streamLen = aCount;

    if (streamLen == 0)
    {
        NS_ERROR("count of zero passed to OnDataAvailable");
        return NS_ERROR_UNEXPECTED;
    }

    if (mStreamEnded)
    {
        // Hmm... this may just indicate that the data stream is done and that
        // what's left is either metadata or padding of some sort.... throwing
        // it out is probably the safe thing to do.
        PRUint32 n;
        return iStr->ReadSegments(NS_DiscardSegment, nsnull, streamLen, &n);
    }

    switch (mMode)
    {
    case HTTP_COMPRESS_GZIP:
        streamLen = check_header(iStr, streamLen, &rv);

        if (rv != NS_OK)
            return rv;

        if (streamLen == 0)
            return NS_OK;

    // FALLTHROUGH

    case HTTP_COMPRESS_DEFLATE:

        if (mInpBuffer != NULL && streamLen > mInpBufferLen)
        {
            mInpBuffer = (unsigned char *) nsMemory::Realloc(mInpBuffer, mInpBufferLen = streamLen);

            if (mOutBufferLen < streamLen * 2)
                mOutBuffer = (unsigned char *) nsMemory::Realloc(mOutBuffer, mOutBufferLen = streamLen * 3);

            if (mInpBuffer == NULL || mOutBuffer == NULL)
                return NS_ERROR_OUT_OF_MEMORY;
        }

        if (mInpBuffer == NULL)
            mInpBuffer = (unsigned char *) nsMemory::Alloc(mInpBufferLen = streamLen);

        if (mOutBuffer == NULL)
            mOutBuffer = (unsigned char *) nsMemory::Alloc(mOutBufferLen = streamLen * 3);

        if (mInpBuffer == NULL || mOutBuffer == NULL)
            return NS_ERROR_OUT_OF_MEMORY;

        iStr->Read((char *)mInpBuffer, streamLen, &rv);

        if (NS_FAILED(rv))
            return rv;

        if (mMode == HTTP_COMPRESS_DEFLATE)
        {
            if (!mStreamInitialized)
            {
                memset(&d_stream, 0, sizeof (d_stream));

                if (inflateInit(&d_stream) != Z_OK)
                    return NS_ERROR_FAILURE;

                mStreamInitialized = true;
            }
            d_stream.next_in = mInpBuffer;
            d_stream.avail_in = (uInt)streamLen;

            mDummyStreamInitialised = false;
            for (;;)
            {
                d_stream.next_out = mOutBuffer;
                d_stream.avail_out = (uInt)mOutBufferLen;

                int code = inflate(&d_stream, Z_NO_FLUSH);
                unsigned bytesWritten = (uInt)mOutBufferLen - d_stream.avail_out;

                if (code == Z_STREAM_END)
                {
                    if (bytesWritten)
                    {
                        rv = do_OnDataAvailable(request, aContext, aSourceOffset, (char *)mOutBuffer, bytesWritten);
                        if (NS_FAILED (rv))
                            return rv;
                    }

                    inflateEnd(&d_stream);
                    mStreamEnded = true;
                    break;
                }
                else if (code == Z_OK)
                {
                    if (bytesWritten)
                    {
                        rv = do_OnDataAvailable(request, aContext, aSourceOffset, (char *)mOutBuffer, bytesWritten);
                        if (NS_FAILED (rv))
                            return rv;
                    }
                }
                else if (code == Z_BUF_ERROR)
                {
                    if (bytesWritten)
                    {
                        rv = do_OnDataAvailable(request, aContext, aSourceOffset, (char *)mOutBuffer, bytesWritten);
                        if (NS_FAILED (rv))
                            return rv;
                    }
                    break;
                }
                else if (code == Z_DATA_ERROR)
                {
                    // some servers (notably Apache with mod_deflate) don't generate zlib headers
                    // insert a dummy header and try again
                    static char dummy_head[2] =
                    {
                        0x8 + 0x7 * 0x10,
                        (((0x8 + 0x7 * 0x10) * 0x100 + 30) / 31 * 31) & 0xFF,
                    };
                    inflateReset(&d_stream);
                    d_stream.next_in = (Bytef*) dummy_head;
                    d_stream.avail_in = sizeof(dummy_head);

                    code = inflate(&d_stream, Z_NO_FLUSH);
                    if (code != Z_OK)
                        return NS_ERROR_FAILURE;

                    // stop an endless loop caused by non-deflate data being labelled as deflate
                    if (mDummyStreamInitialised) {
                        NS_WARNING("endless loop detected"
                                   " - invalid deflate");
                        return NS_ERROR_INVALID_CONTENT_ENCODING;
                    }
                    mDummyStreamInitialised = true;
                    // reset stream pointers to our original data
                    d_stream.next_in = mInpBuffer;
                    d_stream.avail_in = (uInt)streamLen;
                }
                else
                    return NS_ERROR_INVALID_CONTENT_ENCODING;
            } /* for */
        }
        else
        {
            if (!mStreamInitialized)
            {
                memset(&d_stream, 0, sizeof (d_stream));

                if (inflateInit2(&d_stream, -MAX_WBITS) != Z_OK)
                    return NS_ERROR_FAILURE;

                mStreamInitialized = true;
            }

            d_stream.next_in  = mInpBuffer;
            d_stream.avail_in = (uInt)streamLen;

            for (;;)
            {
                d_stream.next_out  = mOutBuffer;
                d_stream.avail_out = (uInt)mOutBufferLen;

                int code = inflate (&d_stream, Z_NO_FLUSH);
                unsigned bytesWritten = (uInt)mOutBufferLen - d_stream.avail_out;

                if (code == Z_STREAM_END)
                {
                    if (bytesWritten)
                    {
                        rv = do_OnDataAvailable(request, aContext, aSourceOffset, (char *)mOutBuffer, bytesWritten);
                        if (NS_FAILED (rv))
                            return rv;
                    }

                    inflateEnd(&d_stream);
                    mStreamEnded = true;
                    break;
                }
                else if (code == Z_OK)
                {
                    if (bytesWritten)
                    {
                        rv = do_OnDataAvailable(request, aContext, aSourceOffset, (char *)mOutBuffer, bytesWritten);
                        if (NS_FAILED (rv))
                            return rv;
                    }
                }
                else if (code == Z_BUF_ERROR)
                {
                    if (bytesWritten)
                    {
                        rv = do_OnDataAvailable(request, aContext, aSourceOffset, (char *)mOutBuffer, bytesWritten);
                        if (NS_FAILED (rv))
                            return rv;
                    }
                    break;
                }
                else
                    return NS_ERROR_INVALID_CONTENT_ENCODING;
            } /* for */
        } /* gzip */
        break;

    default:
        rv = mListener->OnDataAvailable(request, aContext, iStr, aSourceOffset, aCount);
        if (NS_FAILED (rv))
            return rv;
    } /* switch */

    return NS_OK;
} /* OnDataAvailable */
Beispiel #24
0
nsresult nsMsgThread::GetChildHdrForKey(nsMsgKey desiredKey, nsIMsgDBHdr **result, int32_t *resultIndex)
{
  uint32_t numChildren;
  uint32_t childIndex = 0;
  nsresult rv = NS_OK;        // XXX or should this default to an error?

  NS_ENSURE_ARG_POINTER(result);

  GetNumChildren(&numChildren);

  if ((int32_t) numChildren < 0)
    numChildren = 0;

  for (childIndex = 0; childIndex < numChildren; childIndex++)
  {
    rv = GetChildHdrAt(childIndex, result);
    if (NS_SUCCEEDED(rv) && *result)
    {
      nsMsgKey msgKey;
      // we're only doing one level of threading, so check if caller is
      // asking for children of the first message in the thread or not.
      // if not, we will tell him there are no children.
      (*result)->GetMessageKey(&msgKey);

      if (msgKey == desiredKey)
      {
        nsMsgKey threadKey;
        (*result)->GetThreadId(&threadKey);
        if (threadKey != m_threadKey) // this msg isn't in this thread
        {
          NS_WARNING("msg in wrong thread - this shouldn't happen");
          uint32_t msgSize;
          (*result)->GetMessageSize(&msgSize);
          if (msgSize == 0) // this is a phantom message - let's get rid of it.
          {
            RemoveChild(msgKey);
            rv = NS_ERROR_UNEXPECTED;
          }
          else
          {
            // otherwise, let's try to figure out which thread
            // this message really belongs to.
            nsCOMPtr<nsIMsgThread> threadKeyThread = 
                  dont_AddRef(m_mdbDB->GetThreadForThreadId(threadKey));
            if (threadKeyThread)
            {
              nsCOMPtr<nsIMsgDBHdr> otherThreadHdr;
              threadKeyThread->GetChild(msgKey, getter_AddRefs(otherThreadHdr));
              if (otherThreadHdr)
              {
                // Message is in one thread but has a different thread id.
                // Remove it from the thread and then rethread it.
                RemoveChild(msgKey);
                threadKeyThread->RemoveChildHdr(otherThreadHdr, nullptr);
                bool newThread;
                nsMsgHdr* msgHdr = static_cast<nsMsgHdr*>(otherThreadHdr.get());
                m_mdbDB->ThreadNewHdr(msgHdr, newThread);
              }
              else
              {
                (*result)->SetThreadId(m_threadKey);
              }
            }
          }
        }
        break;
      }
      NS_RELEASE(*result);
    }
  }
  if (resultIndex)
    *resultIndex = childIndex;

  return rv;
}
Beispiel #25
0
// moved almost verbatim from mimehdrs.cpp
// char *
// MimeHeaders_get_parameter (const char *header_value, const char *parm_name,
//                            char **charset, char **language)
//
// The format of these header lines  is
// <token> [ ';' <token> '=' <token-or-quoted-string> ]*
NS_IMETHODIMP 
nsMIMEHeaderParamImpl::GetParameterInternal(const char *aHeaderValue, 
                                            const char *aParamName,
                                            char **aCharset,
                                            char **aLang,
                                            char **aResult)
{
  if (!aHeaderValue ||  !*aHeaderValue || !aResult)
    return NS_ERROR_INVALID_ARG;

  *aResult = nsnull;

  if (aCharset) *aCharset = nsnull;
  if (aLang) *aLang = nsnull;

  const char *str = aHeaderValue;

  // skip leading white space.
  for (; *str &&  nsCRT::IsAsciiSpace(*str); ++str)
    ;
  const char *start = str;
  
  // aParamName is empty. return the first (possibly) _unnamed_ 'parameter'
  // For instance, return 'inline' in the following case:
  // Content-Disposition: inline; filename=.....
  if (!aParamName || !*aParamName) 
    {
      for (; *str && *str != ';' && !nsCRT::IsAsciiSpace(*str); ++str)
        ;
      if (str == start)
        return NS_ERROR_UNEXPECTED;
      *aResult = (char *) nsMemory::Clone(start, (str - start) + 1);
      NS_ENSURE_TRUE(*aResult, NS_ERROR_OUT_OF_MEMORY);
      (*aResult)[str - start] = '\0';  // null-terminate
      return NS_OK;
    }

  /* Skip forward to first ';' */
  for (; *str && *str != ';' && *str != ','; ++str)
    ;
  if (*str)
    str++;
  /* Skip over following whitespace */
  for (; *str && nsCRT::IsAsciiSpace(*str); ++str)
    ;

  // Some broken http servers just specify parameters
  // like 'filename' without specifying disposition
  // method. Rewind to the first non-white-space
  // character.
  
  if (!*str)
    str = start;

  // RFC2231 - The legitimate parm format can be:
  // A. title=ThisIsTitle 
  // B. title*=us-ascii'en-us'This%20is%20wierd.
  // C. title*0*=us-ascii'en'This%20is%20wierd.%20We
  //    title*1*=have%20to%20support%20this.
  //    title*2="Else..."
  // D. title*0="Hey, what you think you are doing?"
  //    title*1="There is no charset and lang info."

  PRInt32 paramLen = strlen(aParamName);

  while (*str) {
    const char *tokenStart = str;
    const char *tokenEnd = 0;
    const char *valueStart = str;
    const char *valueEnd = 0;

    NS_ASSERTION(!nsCRT::IsAsciiSpace(*str), "should be after whitespace.");

    // Skip forward to the end of this token. 
    for (; *str && !nsCRT::IsAsciiSpace(*str) && *str != '=' && *str != ';'; str++)
      ;
    tokenEnd = str;

    // Skip over whitespace, '=', and whitespace
    while (nsCRT::IsAsciiSpace(*str)) ++str;
    if (*str == '=') ++str;
    while (nsCRT::IsAsciiSpace(*str)) ++str;

    PRBool needUnquote = PR_FALSE;
    
    if (*str != '"')
    {
      // The value is a token, not a quoted string.
      valueStart = str;
      for (valueEnd = str;
           *valueEnd && !nsCRT::IsAsciiSpace (*valueEnd) && *valueEnd != ';';
           valueEnd++)
        ;
      str = valueEnd;
    }
    else
    {
      // The value is a quoted string.
      needUnquote = PR_TRUE;
      
      ++str;
      valueStart = str;
      for (valueEnd = str; *valueEnd; ++valueEnd)
      {
        if (*valueEnd == '\\')
          ++valueEnd;
        else if (*valueEnd == '"')
          break;
      }
      str = valueEnd + 1;
    }

    // See if this is the simplest case (case A above),
    // a 'single' line value with no charset and lang.
    // If so, copy it and return.
    if (tokenEnd - tokenStart == paramLen &&
        !nsCRT::strncasecmp(tokenStart, aParamName, paramLen))
    {
      // if the parameter spans across multiple lines we have to strip out the
      //     line continuation -- jht 4/29/98 
      nsCAutoString tempStr(valueStart, valueEnd - valueStart);
      tempStr.StripChars("\r\n");
      char *res = ToNewCString(tempStr);
      NS_ENSURE_TRUE(res, NS_ERROR_OUT_OF_MEMORY);
      
      if (needUnquote)
        RemoveQuotedStringEscapes(res);
            
      *aResult = res;
      
      // keep going, we may find a RFC 2231 encoded alternative
    }
    // case B, C, and D
    else if (tokenEnd - tokenStart > paramLen &&
             !nsCRT::strncasecmp(tokenStart, aParamName, paramLen) &&
             *(tokenStart + paramLen) == '*')
    {
      const char *cp = tokenStart + paramLen + 1; // 1st char pass '*'
      PRBool needUnescape = *(tokenEnd - 1) == '*';
      // the 1st line of a multi-line parameter or a single line  that needs 
      // unescaping. ( title*0*=  or  title*= )
      if ((*cp == '0' && needUnescape) || (tokenEnd - tokenStart == paramLen + 1))
      {
        // look for single quotation mark(')
        const char *sQuote1 = PL_strchr(valueStart, 0x27);
        const char *sQuote2 = (char *) (sQuote1 ? PL_strchr(sQuote1 + 1, 0x27) : nsnull);

        // Two single quotation marks must be present even in
        // absence of charset and lang. 
        if (!sQuote1 || !sQuote2)
          NS_WARNING("Mandatory two single quotes are missing in header parameter\n");
        if (aCharset && sQuote1 > valueStart && sQuote1 < valueEnd)
        {
          *aCharset = (char *) nsMemory::Clone(valueStart, sQuote1 - valueStart + 1);
          if (*aCharset) 
            *(*aCharset + (sQuote1 - valueStart)) = 0;
        }
        if (aLang && sQuote1 && sQuote2 && sQuote2 > sQuote1 + 1 &&
            sQuote2 < valueEnd)
        {
          *aLang = (char *) nsMemory::Clone(sQuote1 + 1, sQuote2 - (sQuote1 + 1) + 1);
          if (*aLang) 
            *(*aLang + (sQuote2 - (sQuote1 + 1))) = 0;
        }

        // Be generous and handle gracefully when required 
        // single quotes are absent.
        if (sQuote1)
        {
          if(!sQuote2)
            sQuote2 = sQuote1;
        }
        else
          sQuote2 = valueStart - 1;

        if (sQuote2 && sQuote2 + 1 < valueEnd)
        {
          if (*aResult)
          {
            // drop non-2231-encoded value, instead prefer the one using
            // the RFC2231 encoding
            nsMemory::Free(*aResult);
          }
          *aResult = (char *) nsMemory::Alloc(valueEnd - (sQuote2 + 1) + 1);
          if (*aResult)
          {
            memcpy(*aResult, sQuote2 + 1, valueEnd - (sQuote2 + 1));
            *(*aResult + (valueEnd - (sQuote2 + 1))) = 0;
            if (needUnescape)
            {
              nsUnescape(*aResult);
              if (tokenEnd - tokenStart == paramLen + 1)
                // we're done; this is case B 
                return NS_OK; 
            }
          }
        }
      }  // end of if-block :  title*0*=  or  title*= 
      // a line of multiline param with no need for unescaping : title*[0-9]=
      // or 2nd or later lines of a multiline param : title*[1-9]*= 
      else if (nsCRT::IsAsciiDigit(PRUnichar(*cp)))
      {
        PRInt32 len = 0;
        if (*aResult) // 2nd or later lines of multiline parameter
        {
          len = strlen(*aResult);
          char *ns = (char *) nsMemory::Realloc(*aResult, len + (valueEnd - valueStart) + 1);
          if (!ns)
          {
            nsMemory::Free(*aResult);
          }
          *aResult = ns;
        }
        else if (*cp == '0') // must be; 1st line :  title*0=
        {
          *aResult = (char *) nsMemory::Alloc(valueEnd - valueStart + 1);
        }
        // else {} something is really wrong; out of memory
        if (*aResult)
        {
          // append a partial value
          memcpy(*aResult + len, valueStart, valueEnd - valueStart);
          *(*aResult + len + (valueEnd - valueStart)) = 0;
          if (needUnescape)
            nsUnescape(*aResult + len);
        }
        else 
          return NS_ERROR_OUT_OF_MEMORY;
      } // end of if-block :  title*[0-9]= or title*[1-9]*=
    }

    // str now points after the end of the value.
    //   skip over whitespace, ';', whitespace.
      
    while (nsCRT::IsAsciiSpace(*str)) ++str;
    if (*str == ';') ++str;
    while (nsCRT::IsAsciiSpace(*str)) ++str;
  }

  if (*aResult) 
    return NS_OK;
  else
    return NS_ERROR_INVALID_ARG; // aParameter not found !!
}
Beispiel #26
0
NS_IMETHODIMP nsMsgThread::GetRootHdr(int32_t *resultIndex, nsIMsgDBHdr **result)
{
  NS_ENSURE_ARG_POINTER(result);

  *result = nullptr;
  nsresult rv = NS_OK;

  if (m_threadRootKey != nsMsgKey_None)
  {
    rv = GetChildHdrForKey(m_threadRootKey, result, resultIndex);
    if (NS_SUCCEEDED(rv) && *result)
    {
      // check that we're really the root key.
      nsMsgKey parentKey;
      (*result)->GetThreadParent(&parentKey);
      if (parentKey == nsMsgKey_None)
        return rv;
      NS_RELEASE(*result);
    }
#ifdef DEBUG_David_Bienvenu
    printf("need to reset thread root key\n");
#endif
    uint32_t numChildren;
    nsMsgKey threadParentKey = nsMsgKey_None;
    GetNumChildren(&numChildren);

    for (int32_t childIndex = 0; childIndex < (int32_t) numChildren; childIndex++)
    {
      nsCOMPtr <nsIMsgDBHdr> curChild;
      rv  = GetChildHdrAt(childIndex, getter_AddRefs(curChild));
      if (NS_SUCCEEDED(rv) && curChild)
      {
        nsMsgKey parentKey;

        curChild->GetThreadParent(&parentKey);
        if (parentKey == nsMsgKey_None)
        {
          curChild->GetMessageKey(&threadParentKey);
          if (*result)
          {
            NS_WARNING("two top level msgs, not good");
            continue;
          }
          SetThreadRootKey(threadParentKey);
          if (resultIndex)
            *resultIndex = childIndex;
          NS_ADDREF(*result = curChild);
          ReparentMsgsWithInvalidParent(numChildren, threadParentKey);
          //            return NS_OK;
        }
      }
    }
  }
  if (!*result)
  {
    // if we can't get the thread root key, we'll just get the first hdr.
    // there's a bug where sometimes we weren't resetting the thread root key
    // when removing the thread root key.
    if (resultIndex)
      *resultIndex = 0;
    rv = GetChildHdrAt(0, result);
  }
  if (!*result)
    return rv;
  // Check that the thread id of the message is this thread.
  nsMsgKey threadId = nsMsgKey_None;
  (void)(*result)->GetThreadId(&threadId);
  if (threadId != m_threadKey)
    (*result)->SetThreadId(m_threadKey);
  return rv;
}
bool
WaveReader::LoadFormatChunk(uint32_t aChunkSize)
{
  uint32_t rate, channels, frameSize, sampleFormat;
  char waveFormat[WAVE_FORMAT_CHUNK_SIZE];
  const char* p = waveFormat;

  // RIFF chunks are always word (two byte) aligned.
  NS_ABORT_IF_FALSE(mDecoder->GetResource()->Tell() % 2 == 0,
                    "LoadFormatChunk called with unaligned resource");

  if (!ReadAll(waveFormat, sizeof(waveFormat))) {
    return false;
  }

  PR_STATIC_ASSERT(sizeof(uint16_t) +
                   sizeof(uint16_t) +
                   sizeof(uint32_t) +
                   4 +
                   sizeof(uint16_t) +
                   sizeof(uint16_t) <= sizeof(waveFormat));
  if (ReadUint16LE(&p) != WAVE_FORMAT_ENCODING_PCM) {
    NS_WARNING("WAVE is not uncompressed PCM, compressed encodings are not supported");
    return false;
  }

  channels = ReadUint16LE(&p);
  rate = ReadUint32LE(&p);

  // Skip over average bytes per second field.
  p += 4;

  frameSize = ReadUint16LE(&p);

  sampleFormat = ReadUint16LE(&p);

  // PCM encoded WAVEs are not expected to have an extended "format" chunk,
  // but I have found WAVEs that have a extended "format" chunk with an
  // extension size of 0 bytes.  Be polite and handle this rather than
  // considering the file invalid.  This code skips any extension of the
  // "format" chunk.
  if (aChunkSize > WAVE_FORMAT_CHUNK_SIZE) {
    char extLength[2];
    const char* p = extLength;

    if (!ReadAll(extLength, sizeof(extLength))) {
      return false;
    }

    PR_STATIC_ASSERT(sizeof(uint16_t) <= sizeof(extLength));
    uint16_t extra = ReadUint16LE(&p);
    if (aChunkSize - (WAVE_FORMAT_CHUNK_SIZE + 2) != extra) {
      NS_WARNING("Invalid extended format chunk size");
      return false;
    }
    extra += extra % 2;

    if (extra > 0) {
      PR_STATIC_ASSERT(UINT16_MAX + (UINT16_MAX % 2) < UINT_MAX / sizeof(char));
      nsAutoArrayPtr<char> chunkExtension(new char[extra]);
      if (!ReadAll(chunkExtension.get(), extra)) {
        return false;
      }
    }
  }

  // RIFF chunks are always word (two byte) aligned.
  NS_ABORT_IF_FALSE(mDecoder->GetResource()->Tell() % 2 == 0,
                    "LoadFormatChunk left resource unaligned");

  // Make sure metadata is fairly sane.  The rate check is fairly arbitrary,
  // but the channels check is intentionally limited to mono or stereo
  // because that's what the audio backend currently supports.
  unsigned int actualFrameSize = sampleFormat == 8 ? 1 : 2 * channels;
  if (rate < 100 || rate > 96000 ||
      channels < 1 || channels > MAX_CHANNELS ||
      (frameSize != 1 && frameSize != 2 && frameSize != 4) ||
      (sampleFormat != 8 && sampleFormat != 16) ||
      frameSize != actualFrameSize) {
    NS_WARNING("Invalid WAVE metadata");
    return false;
  }

  ReentrantMonitorAutoEnter monitor(mDecoder->GetReentrantMonitor());
  mSampleRate = rate;
  mChannels = channels;
  mFrameSize = frameSize;
  if (sampleFormat == 8) {
    mSampleFormat = FORMAT_U8;
  } else {
    mSampleFormat = FORMAT_S16;
  }
  return true;
}
Beispiel #28
0
nsresult nsProfileLock::Lock(nsIFile* aProfileDir,
                             nsIProfileUnlocker* *aUnlocker)
{
#if defined (XP_MACOSX)
    NS_NAMED_LITERAL_STRING(LOCKFILE_NAME, ".parentlock");
    NS_NAMED_LITERAL_STRING(OLD_LOCKFILE_NAME, "parent.lock");
#elif defined (XP_UNIX)
    NS_NAMED_LITERAL_STRING(OLD_LOCKFILE_NAME, "lock");
    NS_NAMED_LITERAL_STRING(LOCKFILE_NAME, ".parentlock");
#else
    NS_NAMED_LITERAL_STRING(LOCKFILE_NAME, "parent.lock");
#endif

    nsresult rv;
    if (aUnlocker)
        *aUnlocker = nullptr;

    NS_ENSURE_STATE(!mHaveLock);

    bool isDir;
    rv = aProfileDir->IsDirectory(&isDir);
    if (NS_FAILED(rv))
        return rv;
    if (!isDir)
        return NS_ERROR_FILE_NOT_DIRECTORY;

    nsCOMPtr<nsIFile> lockFile;
    rv = aProfileDir->Clone(getter_AddRefs(lockFile));
    if (NS_FAILED(rv))
        return rv;

    rv = lockFile->Append(LOCKFILE_NAME);
    if (NS_FAILED(rv))
        return rv;

#if defined(XP_MACOSX)
    // First, try locking using fcntl. It is more reliable on
    // a local machine, but may not be supported by an NFS server.

    rv = LockWithFcntl(lockFile);
    if (NS_FAILED(rv) && (rv != NS_ERROR_FILE_ACCESS_DENIED))
    {
        // If that failed for any reason other than NS_ERROR_FILE_ACCESS_DENIED,
        // assume we tried an NFS that does not support it. Now, try with symlink.
        rv = LockWithSymlink(lockFile, false);
    }

    if (NS_SUCCEEDED(rv))
    {
        // Check for the old-style lock used by pre-mozilla 1.3 builds.
        // Those builds used an earlier check to prevent the application
        // from launching if another instance was already running. Because
        // of that, we don't need to create an old-style lock as well.
        struct LockProcessInfo
        {
            ProcessSerialNumber psn;
            unsigned long launchDate;
        };

        PRFileDesc *fd = nullptr;
        int32_t ioBytes;
        ProcessInfoRec processInfo;
        LockProcessInfo lockProcessInfo;

        rv = lockFile->SetLeafName(OLD_LOCKFILE_NAME);
        if (NS_FAILED(rv))
            return rv;
        rv = lockFile->OpenNSPRFileDesc(PR_RDONLY, 0, &fd);
        if (NS_SUCCEEDED(rv))
        {
            ioBytes = PR_Read(fd, &lockProcessInfo, sizeof(LockProcessInfo));
            PR_Close(fd);

            if (ioBytes == sizeof(LockProcessInfo))
            {
#ifdef __LP64__
                processInfo.processAppRef = nullptr;
#else
                processInfo.processAppSpec = nullptr;
#endif
                processInfo.processName = nullptr;
                processInfo.processInfoLength = sizeof(ProcessInfoRec);
                if (::GetProcessInformation(&lockProcessInfo.psn, &processInfo) == noErr &&
                        processInfo.processLaunchDate == lockProcessInfo.launchDate)
                {
                    return NS_ERROR_FILE_ACCESS_DENIED;
                }
            }
            else
            {
                NS_WARNING("Could not read lock file - ignoring lock");
            }
        }
        rv = NS_OK; // Don't propagate error from OpenNSPRFileDesc.
    }
#elif defined(XP_UNIX)
    // Get the old lockfile name
    nsCOMPtr<nsIFile> oldLockFile;
    rv = aProfileDir->Clone(getter_AddRefs(oldLockFile));
    if (NS_FAILED(rv))
        return rv;
    rv = oldLockFile->Append(OLD_LOCKFILE_NAME);
    if (NS_FAILED(rv))
        return rv;

    // First, try locking using fcntl. It is more reliable on
    // a local machine, but may not be supported by an NFS server.
    rv = LockWithFcntl(lockFile);
    if (NS_SUCCEEDED(rv)) {
        // Check to see whether there is a symlink lock held by an older
        // Firefox build, and also place our own symlink lock --- but
        // mark it "obsolete" so that other newer builds can break the lock
        // if they obtain the fcntl lock
        rv = LockWithSymlink(oldLockFile, true);

        // If the symlink failed for some reason other than it already
        // exists, then something went wrong e.g. the file system
        // doesn't support symlinks, or we don't have permission to
        // create a symlink there.  In such cases we should just
        // continue because it's unlikely there is an old build
        // running with a symlink there and we've already successfully
        // placed a fcntl lock.
        if (rv != NS_ERROR_FILE_ACCESS_DENIED)
            rv = NS_OK;
    }
    else if (rv != NS_ERROR_FILE_ACCESS_DENIED)
    {
        // If that failed for any reason other than NS_ERROR_FILE_ACCESS_DENIED,
        // assume we tried an NFS that does not support it. Now, try with symlink
        // using the old symlink path
        rv = LockWithSymlink(oldLockFile, false);
    }

#elif defined(XP_WIN)
    nsAutoString filePath;
    rv = lockFile->GetPath(filePath);
    if (NS_FAILED(rv))
        return rv;

    lockFile->GetLastModifiedTime(&mReplacedLockTime);

    // always create the profile lock and never delete it so we can use its
    // modification timestamp to detect startup crashes
    mLockFileHandle = CreateFileW(filePath.get(),
                                  GENERIC_READ | GENERIC_WRITE,
                                  0, // no sharing - of course
                                  nullptr,
                                  CREATE_ALWAYS,
                                  0,
                                  nullptr);
    if (mLockFileHandle == INVALID_HANDLE_VALUE) {
        if (aUnlocker) {
            nsRefPtr<mozilla::ProfileUnlockerWin> unlocker(
                new mozilla::ProfileUnlockerWin(filePath));
            if (NS_SUCCEEDED(unlocker->Init())) {
                nsCOMPtr<nsIProfileUnlocker> unlockerInterface(
                    do_QueryObject(unlocker));
                unlockerInterface.forget(aUnlocker);
            }
        }
        return NS_ERROR_FILE_ACCESS_DENIED;
    }
#elif defined(VMS)
    nsAutoCString filePath;
    rv = lockFile->GetNativePath(filePath);
    if (NS_FAILED(rv))
        return rv;

    lockFile->GetLastModifiedTime(&mReplacedLockTime);

    mLockFileDesc = open_noshr(filePath.get(), O_CREAT, 0666);
    if (mLockFileDesc == -1)
    {
        if ((errno == EVMSERR) && (vaxc$errno == RMS$_FLK))
        {
            return NS_ERROR_FILE_ACCESS_DENIED;
        }
        else
        {
            NS_ERROR("Failed to open lock file.");
            return NS_ERROR_FAILURE;
        }
    }
#endif

    mHaveLock = true;

    return rv;
}
Beispiel #29
0
bool MediaOmxReader::DecodeVideoFrame(bool &aKeyframeSkip,
                                      int64_t aTimeThreshold)
{
  NS_ASSERTION(mDecoder->OnDecodeThread(), "Should be on decode thread.");
  EnsureActive();

  // Record number of frames decoded and parsed. Automatically update the
  // stats counters using the AutoNotifyDecoded stack-based class.
  uint32_t parsed = 0, decoded = 0;
  AbstractMediaDecoder::AutoNotifyDecoded autoNotify(mDecoder, parsed, decoded);

  bool doSeek = mVideoSeekTimeUs != -1;
  if (doSeek) {
    aTimeThreshold = mVideoSeekTimeUs;
  }

  TimeStamp start = TimeStamp::Now();

  // Read next frame. Don't let this loop run for too long.
  while ((TimeStamp::Now() - start) < TimeDuration::FromSeconds(MAX_VIDEO_DECODE_SECONDS)) {
    MPAPI::VideoFrame frame;
    frame.mGraphicBuffer = nullptr;
    frame.mShouldSkip = false;
    if (!mOmxDecoder->ReadVideo(&frame, aTimeThreshold, aKeyframeSkip, doSeek)) {
      return false;
    }
    doSeek = false;

    // Ignore empty buffer which stagefright media read will sporadically return
    if (frame.mSize == 0 && !frame.mGraphicBuffer) {
      continue;
    }

    parsed++;
    if (frame.mShouldSkip && mSkipCount < MAX_DROPPED_FRAMES) {
      mSkipCount++;
      continue;
    }

    mSkipCount = 0;

    mVideoSeekTimeUs = -1;
    aKeyframeSkip = false;

    IntRect picture = ToIntRect(mPicture);
    if (frame.Y.mWidth != mInitialFrame.width ||
        frame.Y.mHeight != mInitialFrame.height) {

      // Frame size is different from what the container reports. This is legal,
      // and we will preserve the ratio of the crop rectangle as it
      // was reported relative to the picture size reported by the container.
      picture.x = (mPicture.x * frame.Y.mWidth) / mInitialFrame.width;
      picture.y = (mPicture.y * frame.Y.mHeight) / mInitialFrame.height;
      picture.width = (frame.Y.mWidth * mPicture.width) / mInitialFrame.width;
      picture.height = (frame.Y.mHeight * mPicture.height) / mInitialFrame.height;
    }

    // This is the approximate byte position in the stream.
    int64_t pos = mDecoder->GetResource()->Tell();

    VideoData *v;
    if (!frame.mGraphicBuffer) {

      VideoData::YCbCrBuffer b;
      b.mPlanes[0].mData = static_cast<uint8_t *>(frame.Y.mData);
      b.mPlanes[0].mStride = frame.Y.mStride;
      b.mPlanes[0].mHeight = frame.Y.mHeight;
      b.mPlanes[0].mWidth = frame.Y.mWidth;
      b.mPlanes[0].mOffset = frame.Y.mOffset;
      b.mPlanes[0].mSkip = frame.Y.mSkip;

      b.mPlanes[1].mData = static_cast<uint8_t *>(frame.Cb.mData);
      b.mPlanes[1].mStride = frame.Cb.mStride;
      b.mPlanes[1].mHeight = frame.Cb.mHeight;
      b.mPlanes[1].mWidth = frame.Cb.mWidth;
      b.mPlanes[1].mOffset = frame.Cb.mOffset;
      b.mPlanes[1].mSkip = frame.Cb.mSkip;

      b.mPlanes[2].mData = static_cast<uint8_t *>(frame.Cr.mData);
      b.mPlanes[2].mStride = frame.Cr.mStride;
      b.mPlanes[2].mHeight = frame.Cr.mHeight;
      b.mPlanes[2].mWidth = frame.Cr.mWidth;
      b.mPlanes[2].mOffset = frame.Cr.mOffset;
      b.mPlanes[2].mSkip = frame.Cr.mSkip;

      v = VideoData::Create(mInfo.mVideo,
                            mDecoder->GetImageContainer(),
                            pos,
                            frame.mTimeUs,
                            1, // We don't know the duration.
                            b,
                            frame.mKeyFrame,
                            -1,
                            picture);
    } else {
      v = VideoData::Create(mInfo.mVideo,
                            mDecoder->GetImageContainer(),
                            pos,
                            frame.mTimeUs,
                            1, // We don't know the duration.
                            frame.mGraphicBuffer,
                            frame.mKeyFrame,
                            -1,
                            picture);
    }

    if (!v) {
      NS_WARNING("Unable to create VideoData");
      return false;
    }

    decoded++;
    NS_ASSERTION(decoded <= parsed, "Expect to decode fewer frames than parsed in MediaPlugin...");

    mVideoQueue.Push(v);

    break;
  }

  return true;
}
Beispiel #30
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;
}