Пример #1
0
TEST_F(DeferredImageDecoderTest, decodeOnOtherThread) {
  m_lazyDecoder->setData(m_data, true);
  sk_sp<SkImage> image = m_lazyDecoder->createFrameAtIndex(0);
  ASSERT_TRUE(image);
  EXPECT_EQ(1, image->width());
  EXPECT_EQ(1, image->height());

  SkPictureRecorder recorder;
  SkCanvas* tempCanvas = recorder.beginRecording(100, 100, 0, 0);
  tempCanvas->drawImage(image.get(), 0, 0);
  sk_sp<SkPicture> picture = recorder.finishRecordingAsPicture();
  EXPECT_EQ(0, m_decodeRequestCount);

  // Create a thread to rasterize SkPicture.
  std::unique_ptr<WebThread> thread =
      WTF::wrapUnique(Platform::current()->createThread("RasterThread"));
  thread->getWebTaskRunner()->postTask(
      BLINK_FROM_HERE,
      crossThreadBind(&rasterizeMain,
                      crossThreadUnretained(m_surface->getCanvas()),
                      crossThreadUnretained(picture.get())));
  thread.reset();
  EXPECT_EQ(0, m_decodeRequestCount);

  SkBitmap canvasBitmap;
  canvasBitmap.allocN32Pixels(100, 100);
  ASSERT_TRUE(m_surface->getCanvas()->readPixels(&canvasBitmap, 0, 0));
  SkAutoLockPixels autoLock(canvasBitmap);
  EXPECT_EQ(SkColorSetARGB(255, 255, 255, 255), canvasBitmap.getColor(0, 0));
}
void WorkletBackingThreadHolder::shutdownAndWait() {
  DCHECK(isMainThread());
  WaitableEvent waitableEvent;
  m_thread->backingThread().postTask(
      BLINK_FROM_HERE,
      crossThreadBind(&WorkletBackingThreadHolder::shutdownOnThread,
                      crossThreadUnretained(this),
                      crossThreadUnretained(&waitableEvent)));
  waitableEvent.wait();
}
Пример #3
0
void HTMLParserThread::shutdown() {
  ASSERT(isMainThread());
  ASSERT(s_sharedThread);
  // currentThread will always be non-null in production, but can be null in
  // Chromium unit tests.
  if (Platform::current()->currentThread() && s_sharedThread->m_thread) {
    WaitableEvent waitableEvent;
    s_sharedThread->postTask(
        crossThreadBind(&HTMLParserThread::cleanupHTMLParserThread,
                        crossThreadUnretained(s_sharedThread),
                        crossThreadUnretained(&waitableEvent)));
    waitableEvent.wait();
  }
  delete s_sharedThread;
  s_sharedThread = nullptr;
}
Пример #4
0
void WebSharedWorkerImpl::didTerminateWorkerThread() {
  Platform::current()->mainThread()->getWebTaskRunner()->postTask(
      BLINK_FROM_HERE,
      crossThreadBind(
          &WebSharedWorkerImpl::didTerminateWorkerThreadOnMainThread,
          crossThreadUnretained(this)));
}
Пример #5
0
void WebSharedWorkerImpl::postMessageToPageInspector(const String& message) {
  m_mainFrame->frame()->document()->postInspectorTask(
      BLINK_FROM_HERE,
      createCrossThreadTask(
          &WebSharedWorkerImpl::postMessageToPageInspectorOnMainThread,
          crossThreadUnretained(this), message));
}
WorkletBackingThreadHolder::WorkletBackingThreadHolder(
    std::unique_ptr<WorkerBackingThread> backingThread)
    : m_thread(std::move(backingThread)), m_initialized(false) {
  DCHECK(isMainThread());
  m_thread->backingThread().postTask(
      BLINK_FROM_HERE,
      crossThreadBind(&WorkletBackingThreadHolder::initializeOnThread,
                      crossThreadUnretained(this)));
}
Пример #7
0
void HTMLParserThread::postTask(std::unique_ptr<CrossThreadClosure> closure) {
  ASSERT(isMainThread());
  if (!m_thread) {
    m_thread = WebThreadSupportingGC::create("HTMLParserThread",
                                             BlinkGC::MainThreadHeapMode);
    postTask(crossThreadBind(&HTMLParserThread::setupHTMLParserThread,
                             crossThreadUnretained(this)));
  }

  m_thread->postTask(BLINK_FROM_HERE, std::move(closure));
}
Пример #8
0
void ServiceWorkerGlobalScopeProxy::postMessageToPageInspector(
    const String& message) {
  DCHECK(m_embeddedWorker);
  // The TaskType of Inspector tasks need to be Unthrottled because they need to
  // run even on a suspended page.
  getParentFrameTaskRunners()
      ->get(TaskType::Unthrottled)
      ->postTask(
          BLINK_FROM_HERE,
          crossThreadBind(&WebEmbeddedWorkerImpl::postMessageToPageInspector,
                          crossThreadUnretained(m_embeddedWorker), message));
}
DataConsumerHandleTestUtil::Thread::Thread(
    const char* name,
    InitializationPolicy initializationPolicy)
    : m_thread(
          WebThreadSupportingGC::create(name, BlinkGC::MainThreadHeapMode)),
      m_initializationPolicy(initializationPolicy),
      m_waitableEvent(wrapUnique(new WaitableEvent())) {
  m_thread->postTask(
      BLINK_FROM_HERE,
      crossThreadBind(&Thread::initialize, crossThreadUnretained(this)));
  m_waitableEvent->wait();
}
Пример #10
0
void DatabaseTracker::closeDatabasesImmediately(SecurityOrigin* origin, const String& name)
{
    String originString = origin->toRawString();
    MutexLocker openDatabaseMapLock(m_openDatabaseMapGuard);
    if (!m_openDatabaseMap)
        return;

    DatabaseNameMap* nameMap = m_openDatabaseMap->get(originString);
    if (!nameMap)
        return;

    DatabaseSet* databaseSet = nameMap->get(name);
    if (!databaseSet)
        return;

    // We have to call closeImmediately() on the context thread.
    for (DatabaseSet::iterator it = databaseSet->begin(); it != databaseSet->end(); ++it)
        (*it)->getDatabaseContext()->getExecutionContext()->postTask(BLINK_FROM_HERE, createCrossThreadTask(&DatabaseTracker::closeOneDatabaseImmediately, crossThreadUnretained(this), originString, name, *it));
}
Пример #11
0
DataConsumerHandleTestUtil::Thread::~Thread() {
  m_thread->postTask(
      BLINK_FROM_HERE,
      crossThreadBind(&Thread::shutdown, crossThreadUnretained(this)));
  m_waitableEvent->wait();
}
Пример #12
0
void ScriptProcessorHandler::process(size_t framesToProcess) {
  // Discussion about inputs and outputs:
  // As in other AudioNodes, ScriptProcessorNode uses an AudioBus for its input
  // and output (see inputBus and outputBus below).  Additionally, there is a
  // double-buffering for input and output which is exposed directly to
  // JavaScript (see inputBuffer and outputBuffer below).  This node is the
  // producer for inputBuffer and the consumer for outputBuffer.  The JavaScript
  // code is the consumer of inputBuffer and the producer for outputBuffer.

  // Get input and output busses.
  AudioBus* inputBus = input(0).bus();
  AudioBus* outputBus = output(0).bus();

  // Get input and output buffers. We double-buffer both the input and output
  // sides.
  unsigned doubleBufferIndex = this->doubleBufferIndex();
  bool isDoubleBufferIndexGood = doubleBufferIndex < 2 &&
                                 doubleBufferIndex < m_inputBuffers.size() &&
                                 doubleBufferIndex < m_outputBuffers.size();
  DCHECK(isDoubleBufferIndexGood);
  if (!isDoubleBufferIndexGood)
    return;

  AudioBuffer* inputBuffer = m_inputBuffers[doubleBufferIndex].get();
  AudioBuffer* outputBuffer = m_outputBuffers[doubleBufferIndex].get();

  // Check the consistency of input and output buffers.
  unsigned numberOfInputChannels = m_internalInputBus->numberOfChannels();
  bool buffersAreGood =
      outputBuffer && bufferSize() == outputBuffer->length() &&
      m_bufferReadWriteIndex + framesToProcess <= bufferSize();

  // If the number of input channels is zero, it's ok to have inputBuffer = 0.
  if (m_internalInputBus->numberOfChannels())
    buffersAreGood =
        buffersAreGood && inputBuffer && bufferSize() == inputBuffer->length();

  DCHECK(buffersAreGood);
  if (!buffersAreGood)
    return;

  // We assume that bufferSize() is evenly divisible by framesToProcess - should
  // always be true, but we should still check.
  bool isFramesToProcessGood = framesToProcess &&
                               bufferSize() >= framesToProcess &&
                               !(bufferSize() % framesToProcess);
  DCHECK(isFramesToProcessGood);
  if (!isFramesToProcessGood)
    return;

  unsigned numberOfOutputChannels = outputBus->numberOfChannels();

  bool channelsAreGood = (numberOfInputChannels == m_numberOfInputChannels) &&
                         (numberOfOutputChannels == m_numberOfOutputChannels);
  DCHECK(channelsAreGood);
  if (!channelsAreGood)
    return;

  for (unsigned i = 0; i < numberOfInputChannels; ++i)
    m_internalInputBus->setChannelMemory(
        i, inputBuffer->getChannelData(i)->data() + m_bufferReadWriteIndex,
        framesToProcess);

  if (numberOfInputChannels)
    m_internalInputBus->copyFrom(*inputBus);

  // Copy from the output buffer to the output.
  for (unsigned i = 0; i < numberOfOutputChannels; ++i)
    memcpy(outputBus->channel(i)->mutableData(),
           outputBuffer->getChannelData(i)->data() + m_bufferReadWriteIndex,
           sizeof(float) * framesToProcess);

  // Update the buffering index.
  m_bufferReadWriteIndex =
      (m_bufferReadWriteIndex + framesToProcess) % bufferSize();

  // m_bufferReadWriteIndex will wrap back around to 0 when the current input
  // and output buffers are full.
  // When this happens, fire an event and swap buffers.
  if (!m_bufferReadWriteIndex) {
    // Avoid building up requests on the main thread to fire process events when
    // they're not being handled.  This could be a problem if the main thread is
    // very busy doing other things and is being held up handling previous
    // requests.  The audio thread can't block on this lock, so we call
    // tryLock() instead.
    MutexTryLocker tryLocker(m_processEventLock);
    if (!tryLocker.locked()) {
      // We're late in handling the previous request. The main thread must be
      // very busy.  The best we can do is clear out the buffer ourself here.
      outputBuffer->zero();
    } else if (context()->getExecutionContext()) {
      // With the realtime context, execute the script code asynchronously
      // and do not wait.
      if (context()->hasRealtimeConstraint()) {
        // Fire the event on the main thread with the appropriate buffer
        // index.
        context()->getExecutionContext()->postTask(
            BLINK_FROM_HERE,
            createCrossThreadTask(&ScriptProcessorHandler::fireProcessEvent,
                                  crossThreadUnretained(this),
                                  m_doubleBufferIndex));
      } else {
        // If this node is in the offline audio context, use the
        // waitable event to synchronize to the offline rendering thread.
        std::unique_ptr<WaitableEvent> waitableEvent =
            wrapUnique(new WaitableEvent());

        context()->getExecutionContext()->postTask(
            BLINK_FROM_HERE,
            createCrossThreadTask(
                &ScriptProcessorHandler::fireProcessEventForOfflineAudioContext,
                crossThreadUnretained(this), m_doubleBufferIndex,
                crossThreadUnretained(waitableEvent.get())));

        // Okay to block the offline audio rendering thread since it is
        // not the actual audio device thread.
        waitableEvent->wait();
      }
    }

    swapBuffers();
  }
}
std::unique_ptr<CompositorMutatorClient> CompositorMutatorImpl::createClient()
{
    std::unique_ptr<CompositorMutatorClient> mutatorClient;
    WaitableEvent doneEvent;
    if (WebThread* compositorThread = Platform::current()->compositorThread()) {
        compositorThread->getWebTaskRunner()->postTask(BLINK_FROM_HERE, crossThreadBind(&createCompositorMutatorClient, crossThreadUnretained(&mutatorClient), crossThreadUnretained(&doneEvent)));
    } else {
        createCompositorMutatorClient(&mutatorClient, &doneEvent);
    }
    // TODO(flackr): Instead of waiting for this event, we may be able to just set the
    // mutator on the CompositorProxyClient directly from the compositor thread before
    // it gets used there. We still need to make sure we only create one mutator though.
    doneEvent.wait();
    return mutatorClient;
}