WebGraphicsContext3DDefaultImpl::WebGraphicsContext3DDefaultImpl()
    : m_initialized(false)
    , m_renderDirectlyToWebView(false)
     , m_texture(0)
     , m_fbo(0)
     , m_depthStencilBuffer(0)
     , m_multisampleFBO(0)
     , m_multisampleDepthStencilBuffer(0)
     , m_multisampleColorBuffer(0)
    , m_boundFBO(0)
#ifdef FLIP_FRAMEBUFFER_VERTICALLY
    , m_scanline(0)
#endif
    , m_boundArrayBuffer(0)
    , m_fragmentCompiler(0)
    , m_vertexCompiler(0)
{
}


File* DataObjectItem::GetAsFile() const {
  if (Kind() != kFileKind)
    return nullptr;

  if (source_ == kInternalSource) {
    if (file_)
      return file_.Get();
    DCHECK(shared_buffer_);
    return nullptr;
  }

  DCHECK_EQ(source_, kClipboardSource);
  if (GetType() == kMimeTypeImagePng) {
    SkBitmap bitmap = SystemClipboard::GetInstance().ReadImage(
        mojom::ClipboardBuffer::kStandard);

     SkPixmap pixmap;
     bitmap.peekPixels(&pixmap);

    Vector<uint8_t> png_data;
     SkPngEncoder::Options options;
    options.fZLibLevel = 1;  // Fastest compression.
     if (!ImageEncoder::Encode(&png_data, pixmap, options))
       return nullptr;

    auto data = std::make_unique<BlobData>();
    data->SetContentType(kMimeTypeImagePng);
    data->AppendBytes(png_data.data(), png_data.size());
    const uint64_t length = data->length();
    auto blob = BlobDataHandle::Create(std::move(data), length);
    return File::Create("image.png", base::Time::Now().ToDoubleT() * 1000.0,
                        std::move(blob));
  }

  return nullptr;
}


void BlobURLRequestJob::HeadersCompleted(int status_code,
                                         const std::string& status_text) {
  std::string status("HTTP/1.1 ");
  status.append(base::IntToString(status_code));
  status.append(" ");
  status.append(status_text);
  status.append("\0\0", 2);
  net::HttpResponseHeaders* headers = new net::HttpResponseHeaders(status);

  if (status_code == kHTTPOk || status_code == kHTTPPartialContent) {
    std::string content_length_header(net::HttpRequestHeaders::kContentLength);
    content_length_header.append(": ");
    content_length_header.append(base::Int64ToString(remaining_bytes_));
    headers->AddHeader(content_length_header);
    if (!blob_data_->content_type().empty()) {
      std::string content_type_header(net::HttpRequestHeaders::kContentType);
      content_type_header.append(": ");
      content_type_header.append(blob_data_->content_type());
      headers->AddHeader(content_type_header);
    }
    if (!blob_data_->content_disposition().empty()) {
      std::string content_disposition_header("Content-Disposition: ");
      content_disposition_header.append(blob_data_->content_disposition());
      headers->AddHeader(content_disposition_header);
    }
  }

  response_info_.reset(new net::HttpResponseInfo());
   response_info_->headers = headers;

   set_expected_content_size(remaining_bytes_);
  NotifyHeadersComplete();
   headers_set_ = true;
 }


 bool TranslateManager::IsTranslatableURL(const GURL& url) {
  return !url.SchemeIs("chrome") && !url.SchemeIs("ftp");
 }


 void VideoRendererBase::FrameReady(VideoDecoder::DecoderStatus status,
                                   scoped_refptr<VideoFrame> frame) {
   base::AutoLock auto_lock(lock_);
   DCHECK_NE(state_, kUninitialized);

  CHECK(pending_read_);
  pending_read_ = false;

  if (status != VideoDecoder::kOk) {
    DCHECK(!frame);
    PipelineStatus error = PIPELINE_ERROR_DECODE;
    if (status == VideoDecoder::kDecryptError)
      error = PIPELINE_ERROR_DECRYPT;

    if (!seek_cb_.is_null()) {
      base::ResetAndReturn(&seek_cb_).Run(error);
      return;
    }

    host()->SetError(error);
    return;
  }

  if (state_ == kStopped || state_ == kError || state_ == kFlushed ||
      state_ == kFlushingDecoder)
    return;

  if (state_ == kFlushing) {
    AttemptFlush_Locked();
    return;
  }

  if (!frame) {
    if (state_ != kSeeking)
      return;

    state_ = kPrerolled;
    base::ResetAndReturn(&seek_cb_).Run(PIPELINE_OK);
    return;
  }

  if (state_ == kSeeking && !frame->IsEndOfStream() &&
      (frame->GetTimestamp() + frame->GetDuration()) <= seek_timestamp_) {
    AttemptRead_Locked();
    return;
  }

  if (!frame->IsEndOfStream()) {
    if (frame->GetTimestamp() > host()->GetDuration())
      frame->SetTimestamp(host()->GetDuration());
    if ((frame->GetTimestamp() + frame->GetDuration()) > host()->GetDuration())
      frame->SetDuration(host()->GetDuration() - frame->GetTimestamp());
  }

  ready_frames_.push_back(frame);
  DCHECK_LE(NumFrames_Locked(), limits::kMaxVideoFrames);
  if (!frame->IsEndOfStream())
    time_cb_.Run(frame->GetTimestamp() + frame->GetDuration());
  frame_available_.Signal();

  PipelineStatistics statistics;
  statistics.video_frames_decoded = 1;
  statistics_cb_.Run(statistics);

  if (NumFrames_Locked() < limits::kMaxVideoFrames && !frame->IsEndOfStream()) {
    AttemptRead_Locked();
    return;
  }

  if (state_ == kSeeking) {
    DCHECK(!current_frame_);
    state_ = kPrerolled;

    if (!ready_frames_.front()->IsEndOfStream()) {
      current_frame_ = ready_frames_.front();
      ready_frames_.pop_front();
    }

    DCHECK(!seek_cb_.is_null());
    base::ResetAndReturn(&seek_cb_).Run(PIPELINE_OK);

    base::AutoUnlock ul(lock_);
    paint_cb_.Run();
  }
}


void ContentSettingsStore::ClearContentSettingsForExtension(
    const std::string& ext_id,
    ExtensionPrefsScope scope) {
  bool notify = false;
   {
     base::AutoLock lock(lock_);
     OriginIdentifierValueMap* map = GetValueMap(ext_id, scope);
      char ext_id_buffer[33];
      base::strlcpy(ext_id_buffer, ext_id.c_str(), sizeof(ext_id_buffer));
      base::debug::Alias(ext_id_buffer);
      CHECK(false);
     }
     notify = !map->empty();
     map->clear();
  }
  if (notify) {
    NotifyOfContentSettingChanged(ext_id, scope != kExtensionPrefsScopeRegular);
  }
}


AudioOutputStream* AudioManagerBase::MakeAudioOutputStreamProxy(
    const AudioParameters& params) {
  DCHECK(GetMessageLoop()->BelongsToCurrentThread());

  scoped_refptr<AudioOutputDispatcher>& dispatcher =
      output_dispatchers_[params];
   if (!dispatcher) {
     base::TimeDelta close_delay =
         base::TimeDelta::FromSeconds(kStreamCloseDelaySeconds);
#if defined(OS_WIN) || defined(OS_MACOSX)
     const CommandLine* cmd_line = CommandLine::ForCurrentProcess();
    if (!cmd_line->HasSwitch(switches::kDisableAudioMixer)) {
       dispatcher = new AudioOutputMixer(this, params, close_delay);
    } else
#endif
    {
       dispatcher = new AudioOutputDispatcherImpl(this, params, close_delay);
     }
   }
  return new AudioOutputProxy(dispatcher);
}


 void ServiceWorkerScriptContext::OnInstallEvent(
     int active_version_embedded_worker_id) {
  DidHandleInstallEvent(current_request_id_);
 }


void SpeechSynthesis::handleSpeakingCompleted(SpeechSynthesisUtterance* utterance, bool errorOccurred)
 {
     ASSERT(utterance);

     bool didJustFinishCurrentUtterance = false;
    if (utterance == currentSpeechUtterance()) {
        m_utteranceQueue.removeFirst();
        didJustFinishCurrentUtterance = true;
    }

    fireEvent(errorOccurred ? EventTypeNames::error : EventTypeNames::end, utterance, 0, String());

    if (didJustFinishCurrentUtterance && !m_utteranceQueue.isEmpty())
        startSpeakingImmediately();
}


bool SoftwareFrameManager::SwapToNewFrame(
    uint32 output_surface_id,
    const cc::SoftwareFrameData* frame_data,
    float frame_device_scale_factor,
    base::ProcessHandle process_handle) {

#ifdef OS_WIN
  scoped_ptr<base::SharedMemory> shared_memory(
      new base::SharedMemory(frame_data->handle, true,
                             process_handle));
#else
  scoped_ptr<base::SharedMemory> shared_memory(
      new base::SharedMemory(frame_data->handle, true));
#endif

   if (base::SharedMemory::IsHandleValid(shared_memory->handle())) {
    const size_t size_in_bytes = 4 * frame_data->size.GetArea();
 #ifdef OS_WIN
     if (!shared_memory->Map(0)) {
       DLOG(ERROR) << "Unable to map renderer memory.";
      RecordAction(
          base::UserMetricsAction("BadMessageTerminate_SharedMemoryManager1"));
      return false;
    }

    if (shared_memory->mapped_size() < size_in_bytes) {
      DLOG(ERROR) << "Shared memory too small for given rectangle";
      RecordAction(
          base::UserMetricsAction("BadMessageTerminate_SharedMemoryManager2"));
      return false;
    }
#else
    if (!shared_memory->Map(size_in_bytes)) {
      DLOG(ERROR) << "Unable to map renderer memory.";
      RecordAction(
          base::UserMetricsAction("BadMessageTerminate_SharedMemoryManager1"));
      return false;
    }
#endif
  }

  scoped_refptr<SoftwareFrame> next_frame(new SoftwareFrame(
      client_,
      output_surface_id,
      frame_data->id,
      frame_device_scale_factor,
      frame_data->size,
      shared_memory.Pass()));
  current_frame_.swap(next_frame);
  return true;
}


base::string16 GenerateKeywordFromNavigationEntry(
    const NavigationEntry* entry,
    const std::string& accept_languages) {
  if (IsFormSubmit(entry))
    return base::string16();

  GURL url = entry->GetUserTypedURL();
  if (!url.is_valid()) {
    url = entry->GetURL();
    if (!url.is_valid())
       return base::string16();
   }

  if (!url.SchemeIs(url::kHttpScheme) || (url.path().length() > 1))
     return base::string16();

   return TemplateURL::GenerateKeyword(url, accept_languages);
 }


void MediaElementAudioSourceNode::process(size_t numberOfFrames)
{
    AudioBus* outputBus = output(0)->bus();

    if (!mediaElement() || !m_sourceNumberOfChannels || !m_sourceSampleRate) {
        outputBus->zero();
        return;
    }

     MutexTryLocker tryLocker(m_processLock);
     if (tryLocker.locked()) {
         if (AudioSourceProvider* provider = mediaElement()->audioSourceProvider()) {
             if (m_multiChannelResampler.get()) {
                 ASSERT(m_sourceSampleRate != sampleRate());
                 m_multiChannelResampler->process(provider, outputBus, numberOfFrames);
            } else {
                 ASSERT(m_sourceSampleRate == sampleRate());
                 provider->provideInput(outputBus, numberOfFrames);
             }
         } else {
            outputBus->zero();
        }
    } else {
        outputBus->zero();
    }
}


WebGraphicsContext3DDefaultImpl::VertexAttribPointerState::VertexAttribPointerState()
    : enabled(false)
    , buffer(0)
    , indx(0)
    , size(0)
    , type(0)
    , normalized(false)
    , stride(0)
    , offset(0)
{
}


void WebGraphicsContext3DDefaultImpl::activeTexture(unsigned long texture)
{
    if (texture < GL_TEXTURE0 || texture > GL_TEXTURE0+32)
        return;

    makeContextCurrent();
    glActiveTexture(texture);
}


bool WebGraphicsContext3DDefaultImpl::angleCreateCompilers()
{
    if (!ShInitialize())
        return false;

    ShBuiltInResources resources;
    ShInitBuiltInResources(&resources);
    getIntegerv(GL_MAX_VERTEX_ATTRIBS, &resources.MaxVertexAttribs);
    getIntegerv(MAX_VERTEX_UNIFORM_VECTORS, &resources.MaxVertexUniformVectors);
    getIntegerv(MAX_VARYING_VECTORS, &resources.MaxVaryingVectors);
    getIntegerv(GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS, &resources.MaxVertexTextureImageUnits);
    getIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &resources.MaxCombinedTextureImageUnits);
    getIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &resources.MaxTextureImageUnits);
    getIntegerv(MAX_FRAGMENT_UNIFORM_VECTORS, &resources.MaxFragmentUniformVectors);
    resources.MaxDrawBuffers = 1;

    m_fragmentCompiler = ShConstructCompiler(SH_FRAGMENT_SHADER, SH_WEBGL_SPEC, &resources);
    m_vertexCompiler = ShConstructCompiler(SH_VERTEX_SHADER, SH_WEBGL_SPEC, &resources);
    return (m_fragmentCompiler && m_vertexCompiler);
}


void WebGraphicsContext3DDefaultImpl::angleDestroyCompilers()
{
    if (m_fragmentCompiler) {
        ShDestruct(m_fragmentCompiler);
        m_fragmentCompiler = 0;
    }
    if (m_vertexCompiler) {
        ShDestruct(m_vertexCompiler);
        m_vertexCompiler = 0;
    }
}


bool WebGraphicsContext3DDefaultImpl::angleValidateShaderSource(ShaderSourceEntry& entry)
{
    entry.isValid = false;
    if (entry.translatedSource) {
        fastFree(entry.translatedSource);
        entry.translatedSource = 0;
    }
    if (entry.log) {
        fastFree(entry.log);
        entry.log = 0;
    }

    ShHandle compiler = 0;
    switch (entry.type) {
    case GL_FRAGMENT_SHADER:
        compiler = m_fragmentCompiler;
        break;
    case GL_VERTEX_SHADER:
        compiler = m_vertexCompiler;
        break;
    }
    if (!compiler)
        return false;

    if (!ShCompile(compiler, &entry.source, 1, SH_OBJECT_CODE)) {
        int logSize = 0;
        ShGetInfo(compiler, SH_INFO_LOG_LENGTH, &logSize);
        if (logSize > 1 && tryFastMalloc(logSize * sizeof(char)).getValue(entry.log))
            ShGetInfoLog(compiler, entry.log);
        return false;
    }

    int length = 0;
    ShGetInfo(compiler, SH_OBJECT_CODE_LENGTH, &length);
    if (length > 1) {
        if (!tryFastMalloc(length * sizeof(char)).getValue(entry.translatedSource))
            return false;
        ShGetObjectCode(compiler, entry.translatedSource);
    }
    entry.isValid = true;
    return true;
}


void WebGraphicsContext3DDefaultImpl::bindBuffer(unsigned long target, WebGLId buffer)
{
    makeContextCurrent();
    if (target == GL_ARRAY_BUFFER)
        m_boundArrayBuffer = buffer;
    glBindBuffer(target, buffer);
}


void WebGraphicsContext3DDefaultImpl::bindFramebuffer(unsigned long target, WebGLId framebuffer)
{
    makeContextCurrent();
    if (!framebuffer)
        framebuffer = (m_attributes.antialias ? m_multisampleFBO : m_fbo);
    if (framebuffer != m_boundFBO) {
        glBindFramebufferEXT(target, framebuffer);
        m_boundFBO = framebuffer;
    }
}


unsigned bytesPerComponent(unsigned type)
{
    switch (type) {
    case GL_BYTE:
    case GL_UNSIGNED_BYTE:
        return 1;
    case GL_SHORT:
    case GL_UNSIGNED_SHORT:
    case GL_UNSIGNED_SHORT_5_6_5:
    case GL_UNSIGNED_SHORT_4_4_4_4:
    case GL_UNSIGNED_SHORT_5_5_5_1:
        return 2;
    case GL_FLOAT:
        return 4;
    default:
        return 4;
    }
}


void WebGraphicsContext3DDefaultImpl::compileShader(WebGLId shader)
{
    makeContextCurrent();

    ShaderSourceMap::iterator result = m_shaderSourceMap.find(shader);
    if (result == m_shaderSourceMap.end()) {
        glCompileShader(shader);
        return;
    }
    ShaderSourceEntry* entry = result->second;
    ASSERT(entry);

    if (!angleValidateShaderSource(*entry))
        return; // Shader didn't validate, don't move forward with compiling translated source

    int shaderLength = entry->translatedSource ? strlen(entry->translatedSource) : 0;
    glShaderSource(shader, 1, const_cast<const char**>(&entry->translatedSource), &shaderLength);
    glCompileShader(shader);

#ifndef NDEBUG
    int compileStatus;
    glGetShaderiv(shader, GL_COMPILE_STATUS, &compileStatus);
    ASSERT(compileStatus == GL_TRUE);
#endif
}


unsigned componentsPerPixel(unsigned format, unsigned type)
{
    switch (type) {
    case GL_UNSIGNED_SHORT_5_6_5:
    case GL_UNSIGNED_SHORT_4_4_4_4:
    case GL_UNSIGNED_SHORT_5_5_5_1:
        return 1;
    default:
        break;
    }
    switch (format) {
    case GL_LUMINANCE:
        return 1;
    case GL_LUMINANCE_ALPHA:
        return 2;
    case GL_RGB:
        return 3;
    case GL_RGBA:
    case GL_BGRA_EXT:
        return 4;
    default:
        return 4;
    }
}


void WebGraphicsContext3DDefaultImpl::copyTexImage2D(unsigned long target, long level, unsigned long internalformat,
                                                     long x, long y, unsigned long width, unsigned long height, long border)
{
    makeContextCurrent();

    bool needsResolve = (m_attributes.antialias && m_boundFBO == m_multisampleFBO);
    if (needsResolve) {
        resolveMultisampledFramebuffer(x, y, width, height);
        glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_fbo);
    }

    glCopyTexImage2D(target, level, internalformat, x, y, width, height, border);

    if (needsResolve)
        glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_boundFBO);
}


void WebGraphicsContext3DDefaultImpl::copyTexSubImage2D(unsigned long target, long level, long xoffset, long yoffset,
                                                        long x, long y, unsigned long width, unsigned long height)
{
    makeContextCurrent();

    bool needsResolve = (m_attributes.antialias && m_boundFBO == m_multisampleFBO);
    if (needsResolve) {
        resolveMultisampledFramebuffer(x, y, width, height);
        glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_fbo);
    }

    glCopyTexSubImage2D(target, level, xoffset, yoffset, x, y, width, height);

    if (needsResolve)
        glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_boundFBO);
}


void WebGraphicsContext3DDefaultImpl::copyTextureToParentTextureCHROMIUM(unsigned id, unsigned id2)
{
}


unsigned WebGraphicsContext3DDefaultImpl::createBuffer()
{
    makeContextCurrent();
    GLuint o;
    glGenBuffersARB(1, &o);
    return o;
}


unsigned WebGraphicsContext3DDefaultImpl::createFramebuffer()
{
    makeContextCurrent();
    GLuint o = 0;
    glGenFramebuffersEXT(1, &o);
    return o;
}


unsigned WebGraphicsContext3DDefaultImpl::createRenderbuffer()
{
    makeContextCurrent();
    GLuint o;
    glGenRenderbuffersEXT(1, &o);
    return o;
}


unsigned WebGraphicsContext3DDefaultImpl::createShader(unsigned long shaderType)
{
    makeContextCurrent();
    ASSERT(shaderType == GL_VERTEX_SHADER || shaderType == GL_FRAGMENT_SHADER);
    unsigned shader = glCreateShader(shaderType);
    if (shader) {
        ShaderSourceMap::iterator result = m_shaderSourceMap.find(shader);
        if (result != m_shaderSourceMap.end())
            delete result->second;
        m_shaderSourceMap.set(shader, new ShaderSourceEntry(shaderType));
    }

    return shader;
}


unsigned WebGraphicsContext3DDefaultImpl::createTexture()
{
    makeContextCurrent();
    GLuint o;
    glGenTextures(1, &o);
    return o;
}


static int createTextureObject(GLenum target)
{
    GLuint texture = 0;
    glGenTextures(1, &texture);
    glBindTexture(target, texture);
    glTexParameterf(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    glTexParameterf(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    return texture;
}


void WebGraphicsContext3DDefaultImpl::deleteBuffer(unsigned buffer)
{
    makeContextCurrent();
    glDeleteBuffersARB(1, &buffer);
}


void WebGraphicsContext3DDefaultImpl::deleteFramebuffer(unsigned framebuffer)
{
    makeContextCurrent();
    glDeleteFramebuffersEXT(1, &framebuffer);
}


void WebGraphicsContext3DDefaultImpl::deleteProgram(unsigned program)
{
    makeContextCurrent();
    glDeleteProgram(program);
}


void WebGraphicsContext3DDefaultImpl::deleteRenderbuffer(unsigned renderbuffer)
{
    makeContextCurrent();
    glDeleteRenderbuffersEXT(1, &renderbuffer);
}


void WebGraphicsContext3DDefaultImpl::deleteTexture(unsigned texture)
{
    makeContextCurrent();
    glDeleteTextures(1, &texture);
}


void WebGraphicsContext3DDefaultImpl::disableVertexAttribArray(unsigned long index)
{
    makeContextCurrent();
    if (index < NumTrackedPointerStates)
        m_vertexAttribPointerState[index].enabled = false;
    glDisableVertexAttribArray(index);
}


void WebGraphicsContext3DDefaultImpl::drawElements(unsigned long mode, unsigned long count, unsigned long type, long offset)
{
    makeContextCurrent();
    glDrawElements(mode, count, type,
                   reinterpret_cast<void*>(static_cast<intptr_t>(offset)));
}


void WebGraphicsContext3DDefaultImpl::enableVertexAttribArray(unsigned long index)
{
    makeContextCurrent();
    if (index < NumTrackedPointerStates)
        m_vertexAttribPointerState[index].enabled = true;
    glEnableVertexAttribArray(index);
}


void WebGraphicsContext3DDefaultImpl::flipVertically(unsigned char* framebuffer,
                                                     unsigned int width,
                                                     unsigned int height)
{
    unsigned char* scanline = m_scanline;
    if (!scanline)
        return;
    unsigned int rowBytes = width * 4;
    unsigned int count = height / 2;
    for (unsigned int i = 0; i < count; i++) {
        unsigned char* rowA = framebuffer + i * rowBytes;
        unsigned char* rowB = framebuffer + (height - i - 1) * rowBytes;
        memcpy(scanline, rowB, rowBytes);
        memcpy(rowB, rowA, rowBytes);
        memcpy(rowA, scanline, rowBytes);
    }
}


void WebGraphicsContext3DDefaultImpl::framebufferRenderbuffer(unsigned long target, unsigned long attachment,
                                                              unsigned long renderbuffertarget, WebGLId buffer)
{
    makeContextCurrent();
    if (attachment == GL_DEPTH_STENCIL_ATTACHMENT) {
        glFramebufferRenderbufferEXT(target, GL_DEPTH_ATTACHMENT, renderbuffertarget, buffer);
        glFramebufferRenderbufferEXT(target, GL_STENCIL_ATTACHMENT, renderbuffertarget, buffer);
    } else
        glFramebufferRenderbufferEXT(target, attachment, renderbuffertarget, buffer);
}


void WebGraphicsContext3DDefaultImpl::generateMipmap(unsigned long target)
{
    makeContextCurrent();
    if (glGenerateMipmapEXT)
        glGenerateMipmapEXT(target);
}


bool WebGraphicsContext3DDefaultImpl::getActiveAttrib(WebGLId program, unsigned long index, ActiveInfo& info)
{
    makeContextCurrent();
    if (!program) {
        synthesizeGLError(GL_INVALID_VALUE);
        return false;
    }
    GLint maxNameLength = -1;
    glGetProgramiv(program, GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, &maxNameLength);
    if (maxNameLength < 0)
        return false;
    GLchar* name = 0;
    if (!tryFastMalloc(maxNameLength * sizeof(GLchar)).getValue(name)) {
        synthesizeGLError(GL_OUT_OF_MEMORY);
        return false;
    }
    GLsizei length = 0;
    GLint size = -1;
    GLenum type = 0;
    glGetActiveAttrib(program, index, maxNameLength,
                      &length, &size, &type, name);
    if (size < 0) {
        fastFree(name);
        return false;
    }
    info.name = WebString::fromUTF8(name, length);
    info.type = type;
    info.size = size;
    fastFree(name);
    return true;
}


bool WebGraphicsContext3DDefaultImpl::getActiveUniform(WebGLId program, unsigned long index, ActiveInfo& info)
{
    makeContextCurrent();
    GLint maxNameLength = -1;
    glGetProgramiv(program, GL_ACTIVE_UNIFORM_MAX_LENGTH, &maxNameLength);
    if (maxNameLength < 0)
        return false;
    GLchar* name = 0;
    if (!tryFastMalloc(maxNameLength * sizeof(GLchar)).getValue(name)) {
        synthesizeGLError(GL_OUT_OF_MEMORY);
        return false;
    }
    GLsizei length = 0;
    GLint size = -1;
    GLenum type = 0;
    glGetActiveUniform(program, index, maxNameLength,
                       &length, &size, &type, name);
    if (size < 0) {
        fastFree(name);
        return false;
    }
    info.name = WebString::fromUTF8(name, length);
    info.type = type;
    info.size = size;
    fastFree(name);
    return true;
}


WebGraphicsContext3D::Attributes WebGraphicsContext3DDefaultImpl::getContextAttributes()
{
    return m_attributes;
}


unsigned long WebGraphicsContext3DDefaultImpl::getError()
{
    if (m_syntheticErrors.size() > 0) {
        ListHashSet<unsigned long>::iterator iter = m_syntheticErrors.begin();
        unsigned long err = *iter;
        m_syntheticErrors.remove(iter);
        return err;
    }

    makeContextCurrent();
    return glGetError();
}


void WebGraphicsContext3DDefaultImpl::getFramebufferAttachmentParameteriv(unsigned long target, unsigned long attachment,
                                                                          unsigned long pname, int* value)
{
    makeContextCurrent();
    if (attachment == GL_DEPTH_STENCIL_ATTACHMENT)
        attachment = GL_DEPTH_ATTACHMENT; // Or GL_STENCIL_ATTACHMENT, either works.
    glGetFramebufferAttachmentParameterivEXT(target, attachment, pname, value);
}


void WebGraphicsContext3DDefaultImpl::getIntegerv(unsigned long pname, int* value)
{
    makeContextCurrent();
    switch (pname) {
    case IMPLEMENTATION_COLOR_READ_FORMAT:
        *value = GL_RGB;
        break;
    case IMPLEMENTATION_COLOR_READ_TYPE:
        *value = GL_UNSIGNED_BYTE;
        break;
    case MAX_FRAGMENT_UNIFORM_VECTORS:
        glGetIntegerv(GL_MAX_FRAGMENT_UNIFORM_COMPONENTS, value);
        *value /= 4;
        break;
    case MAX_VERTEX_UNIFORM_VECTORS:
        glGetIntegerv(GL_MAX_VERTEX_UNIFORM_COMPONENTS, value);
        *value /= 4;
        break;
    case MAX_VARYING_VECTORS:
        glGetIntegerv(GL_MAX_VARYING_FLOATS, value);
        *value /= 4;
        break;
    default:
        glGetIntegerv(pname, value);
    }
}


unsigned int WebGraphicsContext3DDefaultImpl::getPlatformTextureId()
{
    return m_texture;
}


WebString WebGraphicsContext3DDefaultImpl::getProgramInfoLog(WebGLId program)
{
    makeContextCurrent();
    GLint logLength;
    glGetProgramiv(program, GL_INFO_LOG_LENGTH, &logLength);
    if (!logLength)
        return WebString();
    GLchar* log = 0;
    if (!tryFastMalloc(logLength * sizeof(GLchar)).getValue(log))
        return WebString();
    GLsizei returnedLogLength;
    glGetProgramInfoLog(program, logLength, &returnedLogLength, log);
    ASSERT(logLength == returnedLogLength + 1);
    WebString res = WebString::fromUTF8(log, returnedLogLength);
    fastFree(log);
    return res;
}


WebString WebGraphicsContext3DDefaultImpl::getShaderInfoLog(WebGLId shader)
{
    makeContextCurrent();

    ShaderSourceMap::iterator result = m_shaderSourceMap.find(shader);
    if (result != m_shaderSourceMap.end()) {
        ShaderSourceEntry* entry = result->second;
        ASSERT(entry);
        if (!entry->isValid) {
            if (!entry->log)
                return WebString();
            WebString res = WebString::fromUTF8(entry->log, strlen(entry->log));
            return res;
        }
    }

    GLint logLength = 0;
    glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &logLength);
    if (logLength <= 1)
        return WebString();
    GLchar* log = 0;
    if (!tryFastMalloc(logLength * sizeof(GLchar)).getValue(log))
        return WebString();
    GLsizei returnedLogLength;
    glGetShaderInfoLog(shader, logLength, &returnedLogLength, log);
    ASSERT(logLength == returnedLogLength + 1);
    WebString res = WebString::fromUTF8(log, returnedLogLength);
    fastFree(log);
    return res;
}


WebString WebGraphicsContext3DDefaultImpl::getShaderSource(WebGLId shader)
{
    makeContextCurrent();

    ShaderSourceMap::iterator result = m_shaderSourceMap.find(shader);
    if (result != m_shaderSourceMap.end()) {
        ShaderSourceEntry* entry = result->second;
        ASSERT(entry);
        if (!entry->source)
            return WebString();
        WebString res = WebString::fromUTF8(entry->source, strlen(entry->source));
        return res;
    }

    GLint logLength = 0;
    glGetShaderiv(shader, GL_SHADER_SOURCE_LENGTH, &logLength);
    if (logLength <= 1)
        return WebString();
    GLchar* log = 0;
    if (!tryFastMalloc(logLength * sizeof(GLchar)).getValue(log))
        return WebString();
    GLsizei returnedLogLength;
    glGetShaderSource(shader, logLength, &returnedLogLength, log);
    ASSERT(logLength == returnedLogLength + 1);
    WebString res = WebString::fromUTF8(log, returnedLogLength);
    fastFree(log);
    return res;
}


WebString WebGraphicsContext3DDefaultImpl::getString(unsigned long name)
{
    makeContextCurrent();
    return WebString::fromUTF8(reinterpret_cast<const char*>(glGetString(name)));
}


long WebGraphicsContext3DDefaultImpl::getVertexAttribOffset(unsigned long index, unsigned long pname)
{
    makeContextCurrent();
    void* pointer;
    glGetVertexAttribPointerv(index, pname, &pointer);
    return reinterpret_cast<long>(pointer);
}


int WebGraphicsContext3DDefaultImpl::height()
{
    return m_cachedHeight;
}


size_t imageSizeInBytes(unsigned width, unsigned height, unsigned format, unsigned type)
{
    return width * height * bytesPerComponent(type) * componentsPerPixel(format, type);
}


bool WebGraphicsContext3DDefaultImpl::isErrorGeneratedOnOutOfBoundsAccesses()
{
    return false;
}


bool WebGraphicsContext3DDefaultImpl::isGLES2NPOTStrict()
{
    return false;
}


bool WebGraphicsContext3DDefaultImpl::makeContextCurrent()
{
    return m_glContext->MakeCurrent();
}


void* WebGraphicsContext3DDefaultImpl::mapTexSubImage2DCHROMIUM(unsigned target, int level, int xoffset, int yoffset, int width, int height, unsigned format, unsigned type, unsigned access)
{
    return 0;
}


void WebGraphicsContext3DDefaultImpl::prepareTexture()
{
    if (!m_renderDirectlyToWebView) {
        resolveMultisampledFramebuffer(0, 0, m_cachedWidth, m_cachedHeight);
    }
}


bool WebGraphicsContext3DDefaultImpl::readBackFramebuffer(unsigned char* pixels, size_t bufferSize)
{
    if (bufferSize != static_cast<size_t>(4 * width() * height()))
        return false;

    makeContextCurrent();

    resolveMultisampledFramebuffer(0, 0, m_cachedWidth, m_cachedHeight);
    glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_fbo);

    GLint packAlignment = 4;
    bool mustRestorePackAlignment = false;
    glGetIntegerv(GL_PACK_ALIGNMENT, &packAlignment);
    if (packAlignment > 4) {
        glPixelStorei(GL_PACK_ALIGNMENT, 4);
        mustRestorePackAlignment = true;
    }

    glReadPixels(0, 0, m_cachedWidth, m_cachedHeight, GL_BGRA, GL_UNSIGNED_BYTE, pixels);

    if (mustRestorePackAlignment)
        glPixelStorei(GL_PACK_ALIGNMENT, packAlignment);

    glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_boundFBO);

#ifdef FLIP_FRAMEBUFFER_VERTICALLY
    if (pixels)
        flipVertically(pixels, m_cachedWidth, m_cachedHeight);
#endif

    return true;
}


void WebGraphicsContext3DDefaultImpl::readPixels(long x, long y, unsigned long width, unsigned long height, unsigned long format, unsigned long type, void* pixels)
{
    makeContextCurrent();
    glFlush();
    bool needsResolve = (m_attributes.antialias && m_boundFBO == m_multisampleFBO);
    if (needsResolve) {
        resolveMultisampledFramebuffer(x, y, width, height);
        glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_fbo);
        glFlush();
    }

    glReadPixels(x, y, width, height, format, type, pixels);

    if (needsResolve)
        glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_boundFBO);
}


void WebGraphicsContext3DDefaultImpl::renderbufferStorage(unsigned long target,
                                                          unsigned long internalformat,
                                                          unsigned long width,
                                                          unsigned long height)
{
    makeContextCurrent();
    switch (internalformat) {
    case GL_DEPTH_STENCIL:
        internalformat = GL_DEPTH24_STENCIL8_EXT;
        break;
    case GL_DEPTH_COMPONENT16:
        internalformat = GL_DEPTH_COMPONENT;
        break;
    case GL_RGBA4:
    case GL_RGB5_A1:
        internalformat = GL_RGBA;
        break;
    case 0x8D62: // GL_RGB565
        internalformat = GL_RGB;
        break;
    }
    glRenderbufferStorageEXT(target, internalformat, width, height);
}


void WebGraphicsContext3DDefaultImpl::reshape(int width, int height)
{
    m_cachedWidth = width;
    m_cachedHeight = height;
    makeContextCurrent();

    GLenum target = GL_TEXTURE_2D;

    if (!m_texture) {
        m_texture = createTextureObject(target);
        glGenFramebuffersEXT(1, &m_fbo);
        glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_fbo);
        m_boundFBO = m_fbo;
        if (m_attributes.depth || m_attributes.stencil)
            glGenRenderbuffersEXT(1, &m_depthStencilBuffer);
        if (m_attributes.antialias) {
            glGenFramebuffersEXT(1, &m_multisampleFBO);
            glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_multisampleFBO);
            m_boundFBO = m_multisampleFBO;
            glGenRenderbuffersEXT(1, &m_multisampleColorBuffer);
            if (m_attributes.depth || m_attributes.stencil)
                glGenRenderbuffersEXT(1, &m_multisampleDepthStencilBuffer);
        }
    }

    GLint internalColorFormat, colorFormat, internalDepthStencilFormat = 0;
    if (m_attributes.alpha) {
        internalColorFormat = GL_RGBA8;
        colorFormat = GL_RGBA;
    } else {
        internalColorFormat = GL_RGB8;
        colorFormat = GL_RGB;
    }
    if (m_attributes.stencil || m_attributes.depth) {
        if (m_attributes.stencil && m_attributes.depth)
            internalDepthStencilFormat = GL_DEPTH24_STENCIL8_EXT;
        else
            internalDepthStencilFormat = GL_DEPTH_COMPONENT;
    }

    bool mustRestoreFBO = false;

    if (m_attributes.antialias) {
        GLint maxSampleCount;
        glGetIntegerv(GL_MAX_SAMPLES_EXT, &maxSampleCount);
        GLint sampleCount = std::min(8, maxSampleCount);
        if (m_boundFBO != m_multisampleFBO) {
            mustRestoreFBO = true;
            glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_multisampleFBO);
        }
        glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, m_multisampleColorBuffer);
        glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, sampleCount, internalColorFormat, width, height);
        glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_RENDERBUFFER_EXT, m_multisampleColorBuffer);
        if (m_attributes.stencil || m_attributes.depth) {
            glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, m_multisampleDepthStencilBuffer);
            glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, sampleCount, internalDepthStencilFormat, width, height);
            if (m_attributes.stencil)
                glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, m_multisampleDepthStencilBuffer);
            if (m_attributes.depth)
                glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, m_multisampleDepthStencilBuffer);
        }
        glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0);
        GLenum status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
        if (status != GL_FRAMEBUFFER_COMPLETE_EXT) {
            printf("GraphicsContext3D: multisampling framebuffer was incomplete\n");

            notImplemented();
        }
    }

    if (m_boundFBO != m_fbo) {
        glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_fbo);
        mustRestoreFBO = true;
    }
    glBindTexture(target, m_texture);
    glTexImage2D(target, 0, internalColorFormat, width, height, 0, colorFormat, GL_UNSIGNED_BYTE, 0);
    glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, target, m_texture, 0);
    glBindTexture(target, 0);
    if (!m_attributes.antialias && (m_attributes.stencil || m_attributes.depth)) {
        glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, m_depthStencilBuffer);
        glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, internalDepthStencilFormat, width, height);
        if (m_attributes.stencil)
            glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, m_depthStencilBuffer);
        if (m_attributes.depth)
            glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, m_depthStencilBuffer);
        glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0);
    }
    GLenum status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
    if (status != GL_FRAMEBUFFER_COMPLETE_EXT) {
        printf("WebGraphicsContext3DDefaultImpl: framebuffer was incomplete\n");

        notImplemented();
    }

    if (m_attributes.antialias) {
        glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_multisampleFBO);
        if (m_boundFBO == m_multisampleFBO)
            mustRestoreFBO = false;
    }

    GLboolean colorMask[] = {GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE}, depthMask = GL_TRUE, stencilMask = GL_TRUE;
    GLboolean isScissorEnabled = GL_FALSE;
    GLboolean isDitherEnabled = GL_FALSE;
    GLbitfield clearMask = GL_COLOR_BUFFER_BIT;
    glGetBooleanv(GL_COLOR_WRITEMASK, colorMask);
    glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
    if (m_attributes.depth) {
        glGetBooleanv(GL_DEPTH_WRITEMASK, &depthMask);
        glDepthMask(GL_TRUE);
        clearMask |= GL_DEPTH_BUFFER_BIT;
    }
    if (m_attributes.stencil) {
        glGetBooleanv(GL_STENCIL_WRITEMASK, &stencilMask);
        glStencilMask(GL_TRUE);
        clearMask |= GL_STENCIL_BUFFER_BIT;
    }
    isScissorEnabled = glIsEnabled(GL_SCISSOR_TEST);
    glDisable(GL_SCISSOR_TEST);
    isDitherEnabled = glIsEnabled(GL_DITHER);
    glDisable(GL_DITHER);

    glClear(clearMask);

    glColorMask(colorMask[0], colorMask[1], colorMask[2], colorMask[3]);
    if (m_attributes.depth)
        glDepthMask(depthMask);
    if (m_attributes.stencil)
        glStencilMask(stencilMask);
    if (isScissorEnabled)
        glEnable(GL_SCISSOR_TEST);
    else
        glDisable(GL_SCISSOR_TEST);
    if (isDitherEnabled)
        glEnable(GL_DITHER);
    else
        glDisable(GL_DITHER);

    if (mustRestoreFBO)
        glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_boundFBO);

#ifdef FLIP_FRAMEBUFFER_VERTICALLY
    if (m_scanline) {
        delete[] m_scanline;
        m_scanline = 0;
    }
    m_scanline = new unsigned char[width * 4];
#endif // FLIP_FRAMEBUFFER_VERTICALLY
}


void WebGraphicsContext3DDefaultImpl::resolveMultisampledFramebuffer(unsigned x, unsigned y, unsigned width, unsigned height)
{
    if (m_attributes.antialias) {
        bool mustRestoreFBO = (m_boundFBO != m_multisampleFBO);
        glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, m_multisampleFBO);
        glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, m_fbo);
        glBlitFramebufferEXT(x, y, x + width, y + height, x, y, x + width, y + height, GL_COLOR_BUFFER_BIT, GL_LINEAR);
        if (mustRestoreFBO)
            glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_boundFBO);
    }
}


void WebGraphicsContext3DDefaultImpl::shaderSource(WebGLId shader, const char* string)
{
    makeContextCurrent();
    GLint length = string ? strlen(string) : 0;
    ShaderSourceMap::iterator result = m_shaderSourceMap.find(shader);
    if (result != m_shaderSourceMap.end()) {
        ShaderSourceEntry* entry = result->second;
        ASSERT(entry);
        if (entry->source) {
            fastFree(entry->source);
            entry->source = 0;
        }
        if (!tryFastMalloc((length + 1) * sizeof(char)).getValue(entry->source))
            return; // FIXME: generate an error?
        memcpy(entry->source, string, (length + 1) * sizeof(char));
    } else
        glShaderSource(shader, 1, &string, &length);
}


int WebGraphicsContext3DDefaultImpl::sizeInBytes(int type)
{
    switch (type) {
    case GL_BYTE:
        return sizeof(GLbyte);
    case GL_UNSIGNED_BYTE:
        return sizeof(GLubyte);
    case GL_SHORT:
        return sizeof(GLshort);
    case GL_UNSIGNED_SHORT:
        return sizeof(GLushort);
    case GL_INT:
        return sizeof(GLint);
    case GL_UNSIGNED_INT:
        return sizeof(GLuint);
    case GL_FLOAT:
        return sizeof(GLfloat);
    }
    return 0;
}


bool WebGraphicsContext3DDefaultImpl::supportsCopyTextureToParentTextureCHROMIUM()
{
    return false;
}


bool WebGraphicsContext3DDefaultImpl::supportsMapSubCHROMIUM()
{
    return false;
}


void WebGraphicsContext3DDefaultImpl::synthesizeGLError(unsigned long error)
{
    m_syntheticErrors.add(error);
}


void WebGraphicsContext3DDefaultImpl::texImage2D(unsigned target, unsigned level, unsigned internalFormat, unsigned width, unsigned height, unsigned border, unsigned format, unsigned type, const void* pixels)
{
    OwnArrayPtr<uint8> zero;
    if (!pixels) {
        size_t size = imageSizeInBytes(width, height, format, type);
        zero.set(new uint8[size]);
        memset(zero.get(), 0, size);
        pixels = zero.get();
    }
    glTexImage2D(target, level, internalFormat, width, height, border, format, type, pixels);
}


void WebGraphicsContext3DDefaultImpl::unmapBufferSubDataCHROMIUM(const void* mem)
{
}


void WebGraphicsContext3DDefaultImpl::unmapTexSubImage2DCHROMIUM(const void* mem)
{
}


void WebGraphicsContext3DDefaultImpl::vertexAttribPointer(unsigned long indx, int size, int type, bool normalized,
                                                          unsigned long stride, unsigned long offset)
{
    makeContextCurrent();

    if (m_boundArrayBuffer <= 0) {
        return;
    }

    if (indx < NumTrackedPointerStates) {
        VertexAttribPointerState& state = m_vertexAttribPointerState[indx];
        state.buffer = m_boundArrayBuffer;
        state.indx = indx;
        state.size = size;
        state.type = type;
        state.normalized = normalized;
        state.stride = stride;
        state.offset = offset;
    }

    glVertexAttribPointer(indx, size, type, normalized, stride,
                          reinterpret_cast<void*>(static_cast<intptr_t>(offset)));
}


int WebGraphicsContext3DDefaultImpl::width()
{
    return m_cachedWidth;
}


WebGraphicsContext3DDefaultImpl::~WebGraphicsContext3DDefaultImpl()
{
    if (m_initialized) {
        makeContextCurrent();

        if (m_attributes.antialias) {
            glDeleteRenderbuffersEXT(1, &m_multisampleColorBuffer);
            if (m_attributes.depth || m_attributes.stencil)
                glDeleteRenderbuffersEXT(1, &m_multisampleDepthStencilBuffer);
            glDeleteFramebuffersEXT(1, &m_multisampleFBO);
        } else {
            if (m_attributes.depth || m_attributes.stencil)
                glDeleteRenderbuffersEXT(1, &m_depthStencilBuffer);
        }
        glDeleteTextures(1, &m_texture);
#ifdef FLIP_FRAMEBUFFER_VERTICALLY
        if (m_scanline)
            delete[] m_scanline;
#endif
        glDeleteFramebuffersEXT(1, &m_fbo);

        m_glContext->Destroy();

        for (ShaderSourceMap::iterator ii = m_shaderSourceMap.begin(); ii != m_shaderSourceMap.end(); ++ii) {
            if (ii->second)
                delete ii->second;
        }
        angleDestroyCompilers();
    }
}


DataObjectItem* DataObjectItem::CreateFromClipboard(const String& type,
                                                    uint64_t sequence_number) {
  if (type == kMimeTypeImagePng) {
    return MakeGarbageCollected<DataObjectItem>(kFileKind, type,
                                                sequence_number);
  }
  return MakeGarbageCollected<DataObjectItem>(kStringKind, type,
                                              sequence_number);
}


DataObjectItem* DataObjectItem::CreateFromFile(File* file) {
  DataObjectItem* item =
      MakeGarbageCollected<DataObjectItem>(kFileKind, file->type());
  item->file_ = file;
  return item;
}


DataObjectItem* DataObjectItem::CreateFromFileWithFileSystemId(
    File* file,
    const String& file_system_id) {
  DataObjectItem* item =
      MakeGarbageCollected<DataObjectItem>(kFileKind, file->type());
  item->file_ = file;
  item->file_system_id_ = file_system_id;
  return item;
}


DataObjectItem* DataObjectItem::CreateFromSharedBuffer(
    scoped_refptr<SharedBuffer> buffer,
    const KURL& source_url,
    const String& filename_extension,
    const AtomicString& content_disposition) {
  DataObjectItem* item = MakeGarbageCollected<DataObjectItem>(
      kFileKind,
      MIMETypeRegistry::GetWellKnownMIMETypeForExtension(filename_extension));
  item->shared_buffer_ = std::move(buffer);
  item->filename_extension_ = filename_extension;
  item->title_ = content_disposition;
  item->base_url_ = source_url;
  return item;
}


DataObjectItem* DataObjectItem::CreateFromString(const String& type,
                                                 const String& data) {
  DataObjectItem* item =
      MakeGarbageCollected<DataObjectItem>(kStringKind, type);
  item->data_ = data;
  return item;
}


DataObjectItem* DataObjectItem::CreateFromURL(const String& url,
                                              const String& title) {
  DataObjectItem* item =
      MakeGarbageCollected<DataObjectItem>(kStringKind, kMimeTypeTextURIList);
  item->data_ = url;
  item->title_ = title;
  return item;
}


DataObjectItem::DataObjectItem(ItemKind kind, const String& type)
    : source_(kInternalSource), kind_(kind), type_(type), sequence_number_(0) {}


DataObjectItem::DataObjectItem(ItemKind kind,
                               const String& type,
                               uint64_t sequence_number)
    : source_(kClipboardSource),
      kind_(kind),
      type_(type),
      sequence_number_(sequence_number) {}


String DataObjectItem::FileSystemId() const {
  return file_system_id_;
}


bool DataObjectItem::HasFileSystemId() const {
  return kind_ == kFileKind && !file_system_id_.IsEmpty();
}


void DataObjectItem::Trace(blink::Visitor* visitor) {
  visitor->Trace(file_);
}


std::unique_ptr<ClipboardReader> ClipboardReader::Create(
    const String& mime_type) {
  if (mime_type == kMimeTypeImagePng)
    return std::make_unique<ClipboardImageReader>();
  if (mime_type == kMimeTypeTextPlain)
    return std::make_unique<ClipboardTextReader>();

  return nullptr;
}


void BlobURLRequestJob::AdvanceBytesRead(int result) {
  DCHECK_GT(result, 0);

  current_item_offset_ += result;
  if (current_item_offset_ == item_length_list_[item_index_])
    AdvanceItem();

  remaining_bytes_ -= result;
  DCHECK_GE(remaining_bytes_, 0);

  read_buf_offset_ += result;
  read_buf_remaining_bytes_ -= result;
  DCHECK_GE(read_buf_remaining_bytes_, 0);
}


void BlobURLRequestJob::AdvanceItem() {
  CloseStream();

  item_index_++;
  current_item_offset_ = 0;
}


int BlobURLRequestJob::ComputeBytesToRead() const {
  int64 current_item_remaining_bytes =
      item_length_list_[item_index_] - current_item_offset_;
  int bytes_to_read = (read_buf_remaining_bytes_ > current_item_remaining_bytes)
      ? static_cast<int>(current_item_remaining_bytes)
      : read_buf_remaining_bytes_;
  if (bytes_to_read > remaining_bytes_)
    bytes_to_read = static_cast<int>(remaining_bytes_);
  return bytes_to_read;
}


void BlobURLRequestJob::CountSize() {
  for (; item_index_ < blob_data_->items().size(); ++item_index_) {
    const BlobData::Item& item = blob_data_->items().at(item_index_);
    int64 item_length = static_cast<int64>(item.length());

    if (item.type() == BlobData::TYPE_FILE) {
      ResolveFile(item.file_path());
      return;
    }

    item_length_list_.push_back(item_length);
    total_size_ += item_length;
  }

  item_index_ = 0;

  if (!byte_range_.ComputeBounds(total_size_)) {
    NotifyFailure(net::ERR_REQUEST_RANGE_NOT_SATISFIABLE);
    return;
  }

  remaining_bytes_ = byte_range_.last_byte_position() -
                     byte_range_.first_byte_position() + 1;
  DCHECK_GE(remaining_bytes_, 0);

  if (byte_range_.first_byte_position())
    Seek(byte_range_.first_byte_position());

  NotifySuccess();
}


void BlobURLRequestJob::DidOpen(base::PlatformFileError rv,
                                base::PassPlatformFile file,
                                bool created) {
  if (rv != base::PLATFORM_FILE_OK) {
    NotifyFailure(net::ERR_FAILED);
    return;
  }

  DCHECK(!stream_.get());
  stream_.reset(new net::FileStream(file.ReleaseValue(), kFileOpenFlags));

  const BlobData::Item& item = blob_data_->items().at(item_index_);
  {
    base::ThreadRestrictions::ScopedAllowIO allow_io;
    int64 offset = current_item_offset_ + static_cast<int64>(item.offset());
    if (offset > 0 && offset != stream_->Seek(net::FROM_BEGIN, offset)) {
      NotifyFailure(net::ERR_FAILED);
      return;
    }
  }

  ReadFile(item);
}


void BlobURLRequestJob::DidRead(int result) {
  if (result < 0) {
    NotifyFailure(net::ERR_FAILED);
    return;
  }
  SetStatus(net::URLRequestStatus());  // Clear the IO_PENDING status

  AdvanceBytesRead(result);

  if (!read_buf_remaining_bytes_) {
    int bytes_read = ReadCompleted();
    NotifyReadComplete(bytes_read);
    return;
  }

  int bytes_read = 0;
  if (ReadLoop(&bytes_read))
    NotifyReadComplete(bytes_read);
}


void BlobURLRequestJob::DidResolve(base::PlatformFileError rv,
                                   const base::PlatformFileInfo& file_info) {
  if (rv == base::PLATFORM_FILE_ERROR_NOT_FOUND) {
    NotifyFailure(net::ERR_FILE_NOT_FOUND);
    return;
  } else if (rv != base::PLATFORM_FILE_OK) {
    NotifyFailure(net::ERR_FAILED);
    return;
  }

  const BlobData::Item& item = blob_data_->items().at(item_index_);
  DCHECK(item.type() == BlobData::TYPE_FILE);

  if (!item.expected_modification_time().is_null() &&
      item.expected_modification_time().ToTimeT() !=
          file_info.last_modified.ToTimeT()) {
    NotifyFailure(net::ERR_FILE_NOT_FOUND);
    return;
  }

  int64 item_length = static_cast<int64>(item.length());
  if (item_length == -1)
    item_length = file_info.size;

  item_length_list_.push_back(item_length);
  total_size_ += item_length;

  item_index_++;
  CountSize();
}


bool BlobURLRequestJob::DispatchReadFile(const BlobData::Item& item) {
  if (stream_ != NULL)
    return ReadFile(item);

  base::FileUtilProxy::CreateOrOpen(
      file_thread_proxy_, item.file_path(), kFileOpenFlags,
      callback_factory_.NewCallback(&BlobURLRequestJob::DidOpen));
  SetStatus(net::URLRequestStatus(net::URLRequestStatus::IO_PENDING, 0));
  return false;
}


bool BlobURLRequestJob::GetMimeType(std::string* mime_type) const {
  if (!response_info_.get())
    return false;

  return response_info_->headers->GetMimeType(mime_type);
}


int BlobURLRequestJob::GetResponseCode() const {
  if (!response_info_.get())
    return -1;

  return response_info_->headers->response_code();
}


void BlobURLRequestJob::GetResponseInfo(net::HttpResponseInfo* info) {
  if (response_info_.get())
    *info = *response_info_;
}


void BlobURLRequestJob::NotifyFailure(int error_code) {
  error_ = true;

  if (headers_set_) {
    NotifyDone(net::URLRequestStatus(net::URLRequestStatus::FAILED,
                                     error_code));
    return;
  }

  int status_code = 0;
  std::string status_txt;
  switch (error_code) {
    case net::ERR_ACCESS_DENIED:
      status_code = kHTTPNotAllowed;
      status_txt = kHTTPNotAllowedText;
      break;
    case net::ERR_FILE_NOT_FOUND:
      status_code = kHTTPNotFound;
      status_txt = kHTTPNotFoundText;
      break;
    case net::ERR_METHOD_NOT_SUPPORTED:
      status_code = kHTTPMethodNotAllow;
      status_txt = kHTTPMethodNotAllowText;
      break;
    case net::ERR_REQUEST_RANGE_NOT_SATISFIABLE:
      status_code = kHTTPRequestedRangeNotSatisfiable;
      status_txt = kHTTPRequestedRangeNotSatisfiableText;
      break;
    case net::ERR_FAILED:
      status_code = kHTTPInternalError;
      status_txt = kHTTPInternalErrorText;
      break;
    default:
      DCHECK(false);
      status_code = kHTTPInternalError;
      status_txt = kHTTPInternalErrorText;
      break;
  }
  HeadersCompleted(status_code, status_txt);
}


 void BlobURLRequestJob::NotifySuccess() {
  int status_code = 0;
  std::string status_text;
  if (byte_range_set_ && byte_range_.IsValid()) {
    status_code = kHTTPPartialContent;
    status_text += kHTTPPartialContentText;
  } else {
    status_code = kHTTPOk;
    status_text = kHTTPOKText;
  }
  HeadersCompleted(status_code, status_text);
}


bool BlobURLRequestJob::ReadBytes(const BlobData::Item& item) {
  DCHECK(read_buf_remaining_bytes_ >= bytes_to_read_);

  memcpy(read_buf_->data() + read_buf_offset_,
         &item.data().at(0) + item.offset() + current_item_offset_,
         bytes_to_read_);

  AdvanceBytesRead(bytes_to_read_);
  return true;
}


bool BlobURLRequestJob::ReadFile(const BlobData::Item& item) {
  DCHECK(stream_.get());
  DCHECK(stream_->IsOpen());
  DCHECK(read_buf_remaining_bytes_ >= bytes_to_read_);

  int rv = stream_->Read(read_buf_->data() + read_buf_offset_,
                         bytes_to_read_,
                         &io_callback_);

  if (rv == net::ERR_IO_PENDING) {
    SetStatus(net::URLRequestStatus(net::URLRequestStatus::IO_PENDING, 0));
    return false;
  }

  if (rv < 0) {
    NotifyFailure(net::ERR_FAILED);
    return false;
  }

  if (GetStatus().is_io_pending())
    DidRead(rv);
  else
    AdvanceBytesRead(rv);

  return true;
}


bool BlobURLRequestJob::ReadItem() {
  if (remaining_bytes_ == 0)
    return true;

  if (item_index_ >= blob_data_->items().size()) {
    NotifyFailure(net::ERR_FAILED);
    return false;
  }

  bytes_to_read_ = ComputeBytesToRead();

  if (bytes_to_read_ == 0) {
    AdvanceItem();
    return ReadItem();
  }

  const BlobData::Item& item = blob_data_->items().at(item_index_);
  switch (item.type()) {
    case BlobData::TYPE_DATA:
      return ReadBytes(item);
    case BlobData::TYPE_FILE:
      return DispatchReadFile(item);
    default:
      DCHECK(false);
      return false;
  }
}


bool BlobURLRequestJob::ReadLoop(int* bytes_read) {
  while (remaining_bytes_ > 0 && read_buf_remaining_bytes_ > 0) {
    if (!ReadItem())
      return false;
  }

  *bytes_read = ReadCompleted();
  return true;
}


bool BlobURLRequestJob::ReadRawData(net::IOBuffer* dest,
                                    int dest_size,
                                    int* bytes_read) {
  DCHECK_NE(dest_size, 0);
  DCHECK(bytes_read);
  DCHECK_GE(remaining_bytes_, 0);

  if (error_) {
    *bytes_read = 0;
    return true;
  }

  if (remaining_bytes_ < dest_size)
    dest_size = static_cast<int>(remaining_bytes_);

  if (!dest_size) {
    *bytes_read = 0;
    return true;
  }

  DCHECK(!read_buf_);
  read_buf_ = dest;
  read_buf_offset_ = 0;
  read_buf_size_ = dest_size;
  read_buf_remaining_bytes_ = dest_size;

  return ReadLoop(bytes_read);
}


void BlobURLRequestJob::Seek(int64 offset) {
  for (item_index_ = 0;
       item_index_ < blob_data_->items().size() &&
           offset >= item_length_list_[item_index_];
       ++item_index_) {
    offset -= item_length_list_[item_index_];
  }

  current_item_offset_ = offset;
}


void BlobURLRequestJob::Start() {
  MessageLoop::current()->PostTask(
      FROM_HERE,
      method_factory_.NewRunnableMethod(&BlobURLRequestJob::DidStart));
}


TranslateManager* TranslateManager::GetInstance() {
  return Singleton<TranslateManager>::get();
}


TranslateInfoBarDelegate* TranslateManager::GetTranslateInfoBarDelegate(
    TabContents* tab) {
  for (int i = 0; i < tab->infobar_delegate_count(); ++i) {
    TranslateInfoBarDelegate* delegate =
        tab->GetInfoBarDelegateAt(i)->AsTranslateInfoBarDelegate();
    if (delegate)
      return delegate;
  }
  return NULL;
}


void TranslateManager::InitAcceptLanguages(PrefService* prefs) {
  std::string accept_langs_str = prefs->GetString(prefs::kAcceptLanguages);
  std::vector<std::string> accept_langs_list;
  LanguageSet accept_langs_set;
  base::SplitString(accept_langs_str, ',', &accept_langs_list);
  std::vector<std::string>::const_iterator iter;
  std::string ui_lang =
      GetLanguageCode(g_browser_process->GetApplicationLocale());
  bool is_ui_english = StartsWithASCII(ui_lang, "en-", false);
  for (iter = accept_langs_list.begin();
       iter != accept_langs_list.end(); ++iter) {
    std::string accept_lang(*iter);
    size_t index = iter->find("-");
    if (index != std::string::npos && *iter != "zh-CN" && *iter != "zh-TW")
      accept_lang = iter->substr(0, index);
    if (accept_lang != "en" || is_ui_english)
      accept_langs_set.insert(accept_lang);
  }
  accept_languages_[prefs] = accept_langs_set;
}


void TranslateManager::InitiateTranslation(TabContents* tab,
                                           const std::string& page_lang) {
  PrefService* prefs = tab->profile()->GetPrefs();
  if (!prefs->GetBoolean(prefs::kEnableTranslate))
    return;

  pref_change_registrar_.Init(prefs);

  if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kDisableTranslate))
    return;

  NavigationEntry* entry = tab->controller().GetActiveEntry();
  if (!entry) {
    return;
  }

  if (GetTranslateInfoBarDelegate(tab))
    return;

  std::string target_lang = GetTargetLanguage();
  if (target_lang.empty() || !IsSupportedLanguage(page_lang)) {
    return;
  }

  if (!IsTranslatableURL(entry->url()) || page_lang == target_lang ||
      !TranslatePrefs::CanTranslate(prefs, page_lang, entry->url()) ||
      IsAcceptLanguage(tab, page_lang)) {
    return;
  }

  std::string auto_target_lang;
  if (!tab->profile()->IsOffTheRecord() &&
      TranslatePrefs::ShouldAutoTranslate(prefs, page_lang,
          &auto_target_lang)) {
    TranslatePage(tab, page_lang, auto_target_lang);
    return;
  }

  std::string auto_translate_to = tab->language_state().AutoTranslateTo();
  if (!auto_translate_to.empty()) {
    TranslatePage(tab, page_lang, auto_translate_to);
    return;
  }

  tab->AddInfoBar(TranslateInfoBarDelegate::CreateDelegate(
      TranslateInfoBarDelegate::BEFORE_TRANSLATE, tab,
      page_lang, target_lang));
}


bool TranslateManager::IsAcceptLanguage(TabContents* tab,
                                        const std::string& language) {
  PrefService* pref_service = tab->profile()->GetPrefs();
  PrefServiceLanguagesMap::const_iterator iter =
      accept_languages_.find(pref_service);
  if (iter == accept_languages_.end()) {
    InitAcceptLanguages(pref_service);
    notification_registrar_.Add(this, NotificationType::PROFILE_DESTROYED,
                                Source<Profile>(tab->profile()));
    pref_change_registrar_.Add(prefs::kAcceptLanguages, this);

    iter = accept_languages_.find(pref_service);
  }

  return iter->second.count(language) != 0;
}


void TranslateManager::Observe(NotificationType type,
                               const NotificationSource& source,
                               const NotificationDetails& details) {
  switch (type.value) {
    case NotificationType::NAV_ENTRY_COMMITTED: {
      NavigationController* controller =
          Source<NavigationController>(source).ptr();
      NavigationController::LoadCommittedDetails* load_details =
          Details<NavigationController::LoadCommittedDetails>(details).ptr();
      NavigationEntry* entry = controller->GetActiveEntry();
      if (!entry) {
        NOTREACHED();
        return;
      }
      if (!load_details->is_main_frame &&
          controller->tab_contents()->language_state().translation_declined()) {
        return;
      }
      if (entry->transition_type() != PageTransition::RELOAD &&
          load_details->type != NavigationType::SAME_PAGE) {
        return;
      }
      MessageLoop::current()->PostTask(FROM_HERE,
          method_factory_.NewRunnableMethod(
              &TranslateManager::InitiateTranslationPosted,
              controller->tab_contents()->render_view_host()->process()->id(),
              controller->tab_contents()->render_view_host()->routing_id(),
              controller->tab_contents()->language_state().
                  original_language()));
      break;
    }
    case NotificationType::TAB_LANGUAGE_DETERMINED: {
      TabContents* tab = Source<TabContents>(source).ptr();
      LanguageState& language_state = tab->language_state();
      if (language_state.page_translatable() &&
          !language_state.translation_pending() &&
          !language_state.translation_declined() &&
          !language_state.IsPageTranslated()) {
        std::string language = *(Details<std::string>(details).ptr());
        InitiateTranslation(tab, language);
      }
      break;
    }
    case NotificationType::PAGE_TRANSLATED: {
      TabContents* tab = Source<TabContents>(source).ptr();
      PageTranslatedDetails* page_translated_details =
          Details<PageTranslatedDetails>(details).ptr();
      PageTranslated(tab, page_translated_details);
      break;
    }
    case NotificationType::PROFILE_DESTROYED: {
      Profile* profile = Source<Profile>(source).ptr();
      notification_registrar_.Remove(this, NotificationType::PROFILE_DESTROYED,
                                     source);
      size_t count = accept_languages_.erase(profile->GetPrefs());
      DCHECK(count > 0);
      pref_change_registrar_.Remove(prefs::kAcceptLanguages, this);
      break;
    }
    case NotificationType::PREF_CHANGED: {
      DCHECK(*Details<std::string>(details).ptr() == prefs::kAcceptLanguages);
      PrefService* prefs = Source<PrefService>(source).ptr();
      InitAcceptLanguages(prefs);
      break;
    }
    default:
      NOTREACHED();
  }
}


ACTION(DeleteDataBuffer) {
  delete[] arg0->memory_pointer;
}


ACTION_P2(CaptureStopped, decoder, vc_impl) {
  decoder->OnStopped(vc_impl);
}


ACTION_P3(CreateDataBufferFromCapture, decoder, vc_impl, data_buffer_number) {
  for (int i = 0; i < data_buffer_number; i++) {
    media::VideoCapture::VideoFrameBuffer* buffer;
    buffer = new media::VideoCapture::VideoFrameBuffer();
    buffer->width = arg1.width;
    buffer->height = arg1.height;
    int length = buffer->width * buffer->height * 3 / 2;
    buffer->memory_pointer = new uint8[length];
    buffer->buffer_size = length;
    decoder->OnBufferReady(vc_impl, buffer);
  }
}


  CaptureVideoDecoderTest() {
    message_loop_.reset(new MessageLoop(MessageLoop::TYPE_IO));
    message_loop_proxy_ =
        base::MessageLoopProxy::current().get();
    vc_manager_ = new MockVideoCaptureImplManager();
    media::VideoCaptureCapability capability;
    capability.width = kWidth;
    capability.height = kHeight;
    capability.frame_rate = kFPS;
    capability.expected_capture_delay = 0;
    capability.color = media::VideoCaptureCapability::kI420;
    capability.interlaced = false;

    decoder_ = new CaptureVideoDecoder(message_loop_proxy_,
                                       kVideoStreamId, vc_manager_, capability);
    EXPECT_CALL(statistics_cb_object_, OnStatistics(_))
        .Times(AnyNumber());

    read_cb_ = base::Bind(&CaptureVideoDecoderTest::FrameReady,
                          base::Unretained(this));

    vc_impl_.reset(new MockVideoCaptureImpl(
        kVideoStreamId, message_loop_proxy_, new VideoCaptureMessageFilter()));
  }


  void Initialize() {
    EXPECT_CALL(*this, FrameReady(media::VideoDecoder::kOk, _));
    decoder_->Read(read_cb_);

    EXPECT_CALL(*vc_manager_, AddDevice(_, _))
        .WillOnce(Return(vc_impl_.get()));
    int buffer_count = 1;
    EXPECT_CALL(*vc_impl_, StartCapture(capture_client(), _))
        .Times(1)
        .WillOnce(CreateDataBufferFromCapture(capture_client(),
                                              vc_impl_.get(),
                                              buffer_count));
    EXPECT_CALL(*vc_impl_, FeedBuffer(_))
        .Times(buffer_count)
        .WillRepeatedly(DeleteDataBuffer());

    decoder_->Initialize(NULL,
                         media::NewExpectedStatusCB(media::PIPELINE_OK),
                         NewStatisticsCB());
    message_loop_->RunAllPending();
  }


  MockVideoCaptureImpl(const media::VideoCaptureSessionId id,
                       scoped_refptr<base::MessageLoopProxy> ml_proxy,
                       VideoCaptureMessageFilter* filter)
      : VideoCaptureImpl(id, ml_proxy, filter) {
  }


  media::StatisticsCB NewStatisticsCB() {
    return base::Bind(&media::MockStatisticsCB::OnStatistics,
                      base::Unretained(&statistics_cb_object_));
  }


  void Stop() {
    EXPECT_CALL(*vc_impl_, StopCapture(capture_client()))
        .Times(1)
        .WillOnce(CaptureStopped(capture_client(), vc_impl_.get()));
    EXPECT_CALL(*vc_manager_, RemoveDevice(_, _))
        .WillOnce(Return());
    decoder_->Stop(media::NewExpectedClosure());
    message_loop_->RunAllPending();
  }


  media::VideoCapture::EventHandler* capture_client() {
    return static_cast<media::VideoCapture::EventHandler*>(decoder_);
   }


  void InitializeDecoderSuccessfully() {
    decoder_->Initialize(
        NULL, NewExpectedStatusCB(PIPELINE_OK), NewStatisticsCB());
    message_loop_.RunAllPending();
  }


  StatisticsCB NewStatisticsCB() {
    return base::Bind(&MockStatisticsCB::OnStatistics,
                      base::Unretained(&statistics_cb_));
   }


  RTCVideoDecoderTest() {
    decoder_ = new RTCVideoDecoder(&message_loop_, kUrl);
    renderer_ = new MockVideoRenderer();
    read_cb_ = base::Bind(&RTCVideoDecoderTest::FrameReady,
                          base::Unretained(this));

    DCHECK(decoder_);

    EXPECT_CALL(statistics_cb_, OnStatistics(_))
        .Times(AnyNumber());
  }


  virtual ~RTCVideoDecoderTest() {
    message_loop_.RunAllPending();
  }


ACTION_P(ReturnBuffer, buffer) {
  arg0.Run(buffer);
}


  void DecodeIFrameThenTestFile(const std::string& test_file_name,
                                size_t expected_width,
                                size_t expected_height) {
    Initialize();

    VideoDecoder::DecoderStatus status_a;
    VideoDecoder::DecoderStatus status_b;
    scoped_refptr<VideoFrame> video_frame_a;
    scoped_refptr<VideoFrame> video_frame_b;

    scoped_refptr<DecoderBuffer> buffer = ReadTestDataFile(test_file_name);

    EXPECT_CALL(*demuxer_, Read(_))
        .WillOnce(ReturnBuffer(i_frame_buffer_))
        .WillOnce(ReturnBuffer(buffer))
        .WillRepeatedly(ReturnBuffer(end_of_stream_buffer_));

    EXPECT_CALL(statistics_cb_, OnStatistics(_))
        .Times(2);

    Read(&status_a, &video_frame_a);
    Read(&status_b, &video_frame_b);

    size_t original_width = static_cast<size_t>(kVisibleRect.width());
    size_t original_height = static_cast<size_t>(kVisibleRect.height());

    EXPECT_EQ(status_a, VideoDecoder::kOk);
    EXPECT_EQ(status_b, VideoDecoder::kOk);
    ASSERT_TRUE(video_frame_a);
    ASSERT_TRUE(video_frame_b);
    EXPECT_EQ(original_width, video_frame_a->width());
    EXPECT_EQ(original_height, video_frame_a->height());
    EXPECT_EQ(expected_width, video_frame_b->width());
    EXPECT_EQ(expected_height, video_frame_b->height());
  }


  void DecodeSingleFrame(const scoped_refptr<DecoderBuffer>& buffer,
                         VideoDecoder::DecoderStatus* status,
                         scoped_refptr<VideoFrame>* video_frame) {
    EXPECT_CALL(*demuxer_, Read(_))
        .WillOnce(ReturnBuffer(buffer))
        .WillRepeatedly(ReturnBuffer(end_of_stream_buffer_));

    EXPECT_CALL(statistics_cb_, OnStatistics(_));

    Read(status, video_frame);
  }


  void EnterDecodingState() {
    VideoDecoder::DecoderStatus status;
    scoped_refptr<VideoFrame> video_frame;
    DecodeSingleFrame(i_frame_buffer_, &status, &video_frame);

    EXPECT_EQ(status, VideoDecoder::kOk);
    ASSERT_TRUE(video_frame);
    EXPECT_FALSE(video_frame->IsEndOfStream());
  }


  void EnterEndOfStreamState() {
    scoped_refptr<VideoFrame> video_frame;
    VideoDecoder::DecoderStatus status;
    Read(&status, &video_frame);
    EXPECT_EQ(status, VideoDecoder::kOk);
    ASSERT_TRUE(video_frame);
    EXPECT_TRUE(video_frame->IsEndOfStream());
  }


  FFmpegVideoDecoderTest()
      : decryptor_(new AesDecryptor(&decryptor_client_)),
        decoder_(new FFmpegVideoDecoder(base::Bind(&Identity<MessageLoop*>,
                                                   &message_loop_))),
        demuxer_(new StrictMock<MockDemuxerStream>()),
        read_cb_(base::Bind(&FFmpegVideoDecoderTest::FrameReady,
                            base::Unretained(this))) {
    CHECK(FFmpegGlue::GetInstance());

    decoder_->set_decryptor(decryptor_.get());

    frame_buffer_.reset(new uint8[kCodedSize.GetArea()]);
    end_of_stream_buffer_ = DecoderBuffer::CreateEOSBuffer();
    i_frame_buffer_ = ReadTestDataFile("vp8-I-frame-320x240");
    corrupt_i_frame_buffer_ = ReadTestDataFile("vp8-corrupt-I-frame");
    encrypted_i_frame_buffer_ = ReadTestDataFile(
        "vp8-encrypted-I-frame-320x240");

    config_.Initialize(kCodecVP8, VIDEO_CODEC_PROFILE_UNKNOWN,
                       kVideoFormat, kCodedSize, kVisibleRect,
                       kFrameRate.num, kFrameRate.den,
                       kAspectRatio.num, kAspectRatio.den,
                       NULL, 0, true);
  }


  void Initialize() {
    InitializeWithConfig(config_);
  }


  void InitializeWithConfigAndStatus(const VideoDecoderConfig& config,
                                     PipelineStatus status) {
    EXPECT_CALL(*demuxer_, video_decoder_config())
        .WillOnce(ReturnRef(config));

    decoder_->Initialize(demuxer_, NewExpectedStatusCB(status),
                         base::Bind(&MockStatisticsCB::OnStatistics,
                                    base::Unretained(&statistics_cb_)));

    message_loop_.RunAllPending();
  }


  void Read(VideoDecoder::DecoderStatus* status,
            scoped_refptr<VideoFrame>* video_frame) {
    EXPECT_CALL(*this, FrameReady(_, _))
        .WillOnce(DoAll(SaveArg<0>(status), SaveArg<1>(video_frame)));

    decoder_->Read(read_cb_);

    message_loop_.RunAllPending();
   }


  void Reset() {
    decoder_->Reset(NewExpectedClosure());
    message_loop_.RunAllPending();
  }


  void Stop() {
    decoder_->Stop(NewExpectedClosure());
    message_loop_.RunAllPending();
  }


void VideoRendererBase::AttemptFlush_Locked() {
  lock_.AssertAcquired();
  DCHECK_EQ(kFlushing, state_);

  ready_frames_.clear();

  if (!pending_paint_ && !pending_read_) {
    state_ = kFlushed;
    current_frame_ = NULL;
    base::ResetAndReturn(&flush_cb_).Run();
  }
}


void VideoRendererBase::AttemptRead_Locked() {
  lock_.AssertAcquired();
  DCHECK_NE(kEnded, state_);

  if (pending_read_ ||
      NumFrames_Locked() == limits::kMaxVideoFrames ||
      (!ready_frames_.empty() && ready_frames_.back()->IsEndOfStream()) ||
      state_ == kFlushingDecoder ||
      state_ == kFlushing) {
    return;
  }

  pending_read_ = true;
  decoder_->Read(base::Bind(&VideoRendererBase::FrameReady, this));
}


base::TimeDelta VideoRendererBase::CalculateSleepDuration(
    const scoped_refptr<VideoFrame>& next_frame,
    float playback_rate) {
  base::TimeDelta now = host()->GetTime();
  base::TimeDelta this_pts = current_frame_->GetTimestamp();
  base::TimeDelta next_pts;
  if (!next_frame->IsEndOfStream()) {
    next_pts = next_frame->GetTimestamp();
  } else {
    next_pts = this_pts + current_frame_->GetDuration();
  }

  base::TimeDelta sleep = next_pts - now;
  return base::TimeDelta::FromMicroseconds(
      static_cast<int64>(sleep.InMicroseconds() / playback_rate));
}


void VideoRendererBase::Flush(const base::Closure& callback) {
  base::AutoLock auto_lock(lock_);
  DCHECK_EQ(state_, kPaused);
  flush_cb_ = callback;
  state_ = kFlushingDecoder;

  base::AutoUnlock auto_unlock(lock_);
  decoder_->Reset(base::Bind(&VideoRendererBase::OnDecoderFlushDone, this));
}


bool VideoRendererBase::HasEnded() {
  base::AutoLock auto_lock(lock_);
  return state_ == kEnded;
}


void VideoRendererBase::Initialize(const scoped_refptr<VideoDecoder>& decoder,
                                   const PipelineStatusCB& status_cb,
                                   const StatisticsCB& statistics_cb,
                                   const TimeCB& time_cb) {
  base::AutoLock auto_lock(lock_);
  DCHECK(decoder);
  DCHECK(!status_cb.is_null());
  DCHECK(!statistics_cb.is_null());
  DCHECK(!time_cb.is_null());
  DCHECK_EQ(kUninitialized, state_);
  decoder_ = decoder;

  statistics_cb_ = statistics_cb;
  time_cb_ = time_cb;

  host()->SetNaturalVideoSize(decoder_->natural_size());

  state_ = kFlushed;

  set_opaque_cb_.Run(!decoder->HasAlpha());
  set_opaque_cb_.Reset();

  if (!base::PlatformThread::Create(0, this, &thread_)) {
    NOTREACHED() << "Video thread creation failed";
    state_ = kError;
    status_cb.Run(PIPELINE_ERROR_INITIALIZATION_FAILED);
    return;
  }

#if defined(OS_WIN)
  ::SetThreadPriority(thread_, THREAD_PRIORITY_ABOVE_NORMAL);
#endif  // defined(OS_WIN)
  status_cb.Run(PIPELINE_OK);
}


int VideoRendererBase::NumFrames_Locked() const {
  lock_.AssertAcquired();
  int outstanding_frames =
      (current_frame_ ? 1 : 0) + (last_available_frame_ ? 1 : 0) +
      (current_frame_ && (current_frame_ == last_available_frame_) ? -1 : 0);
  return ready_frames_.size() + outstanding_frames;
}


void VideoRendererBase::OnDecoderFlushDone() {
  base::AutoLock auto_lock(lock_);
  DCHECK_EQ(kFlushingDecoder, state_);
  DCHECK(!pending_read_);

  state_ = kFlushing;
  AttemptFlush_Locked();
}


void VideoRendererBase::Pause(const base::Closure& callback) {
  base::AutoLock auto_lock(lock_);
  DCHECK(state_ != kUninitialized || state_ == kError);
  state_ = kPaused;
  callback.Run();
}


void VideoRendererBase::Play(const base::Closure& callback) {
  base::AutoLock auto_lock(lock_);
  DCHECK_EQ(kPrerolled, state_);
  state_ = kPlaying;
  callback.Run();
}


void VideoRendererBase::PutCurrentFrame(scoped_refptr<VideoFrame> frame) {
  base::AutoLock auto_lock(lock_);

  if (pending_paint_) {
    DCHECK_EQ(current_frame_, frame);
    DCHECK(!pending_paint_with_last_available_);
    pending_paint_ = false;
  } else if (pending_paint_with_last_available_) {
    DCHECK_EQ(last_available_frame_, frame);
    DCHECK(!pending_paint_);
    pending_paint_with_last_available_ = false;
  } else {
    DCHECK(!frame);
  }

  frame_available_.Signal();
  if (state_ == kFlushingDecoder)
    return;

  if (state_ == kFlushing) {
    AttemptFlush_Locked();
    return;
  }

  if (state_ == kError || state_ == kStopped) {
    DoStopOrError_Locked();
  }
}


void VideoRendererBase::SetPlaybackRate(float playback_rate) {
  base::AutoLock auto_lock(lock_);
  playback_rate_ = playback_rate;
}


void VideoRendererBase::Stop(const base::Closure& callback) {
  if (state_ == kStopped) {
    callback.Run();
    return;
  }

  base::PlatformThreadHandle thread_to_join = base::kNullThreadHandle;
  {
    base::AutoLock auto_lock(lock_);
    state_ = kStopped;

    statistics_cb_.Reset();
    time_cb_.Reset();
    if (!pending_paint_ && !pending_paint_with_last_available_)
      DoStopOrError_Locked();

    if (thread_ != base::kNullThreadHandle) {
      frame_available_.Signal();
      thread_to_join = thread_;
      thread_ = base::kNullThreadHandle;
    }
  }
  if (thread_to_join != base::kNullThreadHandle)
    base::PlatformThread::Join(thread_to_join);

  decoder_->Stop(callback);
}


void VideoRendererBase::ThreadMain() {
  base::PlatformThread::SetName("CrVideoRenderer");

  const base::TimeDelta kIdleTimeDelta =
      base::TimeDelta::FromMilliseconds(10);

  uint32 frames_dropped = 0;

  for (;;) {
    if (frames_dropped > 0) {
      PipelineStatistics statistics;
      statistics.video_frames_dropped = frames_dropped;
      statistics_cb_.Run(statistics);

      frames_dropped = 0;
    }

    base::AutoLock auto_lock(lock_);

    if (state_ == kStopped)
      return;

    if (state_ != kPlaying || playback_rate_ == 0) {
      frame_available_.TimedWait(kIdleTimeDelta);
      continue;
    }

    if (ready_frames_.empty()) {
      frame_available_.TimedWait(kIdleTimeDelta);
      continue;
    }

    if (!current_frame_) {
      if (ready_frames_.front()->IsEndOfStream()) {
        state_ = kEnded;
        host()->NotifyEnded();
        ready_frames_.clear();

        continue;
      }

      frame_available_.TimedWait(kIdleTimeDelta);
      continue;
    }

    base::TimeDelta remaining_time =
        CalculateSleepDuration(ready_frames_.front(), playback_rate_);

    if (remaining_time.InMicroseconds() > 0) {
      remaining_time = std::min(remaining_time, kIdleTimeDelta);
      frame_available_.TimedWait(remaining_time);
      continue;
    }

    if (ready_frames_.front()->IsEndOfStream()) {
      state_ = kEnded;
      host()->NotifyEnded();
      ready_frames_.clear();

      continue;
    }

    if (pending_paint_) {
      while (!ready_frames_.empty()) {
        if (ready_frames_.front()->IsEndOfStream())
          break;

        base::TimeDelta remaining_time =
            ready_frames_.front()->GetTimestamp() - host()->GetTime();

        if (remaining_time.InMicroseconds() > 0)
          break;

        if (!drop_frames_)
          break;

        ++frames_dropped;
        ready_frames_.pop_front();
        AttemptRead_Locked();
      }
      frame_available_.TimedWait(kIdleTimeDelta);
      continue;
    }

    DCHECK(!pending_paint_);
    DCHECK(!ready_frames_.empty());
    current_frame_ = ready_frames_.front();
    ready_frames_.pop_front();
    AttemptRead_Locked();

    base::AutoUnlock auto_unlock(lock_);
    paint_cb_.Run();
  }
}


VideoRendererBase::VideoRendererBase(const base::Closure& paint_cb,
                                     const SetOpaqueCB& set_opaque_cb,
                                     bool drop_frames)
    : frame_available_(&lock_),
      state_(kUninitialized),
      thread_(base::kNullThreadHandle),
      pending_read_(false),
      pending_paint_(false),
      pending_paint_with_last_available_(false),
      drop_frames_(drop_frames),
      playback_rate_(0),
      paint_cb_(paint_cb),
      set_opaque_cb_(set_opaque_cb) {
  DCHECK(!paint_cb_.is_null());
}


VideoRendererBase::~VideoRendererBase() {
  base::AutoLock auto_lock(lock_);
  DCHECK(state_ == kUninitialized || state_ == kStopped) << state_;
 }


void ContentSettingsStore::AddObserver(Observer* observer) {
  DCHECK(OnCorrectThread());
  observers_.AddObserver(observer);
}


ContentSettingsStore::ContentSettingsStore() {
  DCHECK(OnCorrectThread());
}


ContentSettingsStore::FindEntry(const std::string& ext_id) {
  ExtensionEntryMap::iterator i;
  for (i = entries_.begin(); i != entries_.end(); ++i) {
    if (i->second->id == ext_id)
      return i;
  }
  return entries_.end();
}


RuleIterator* ContentSettingsStore::GetRuleIterator(
    ContentSettingsType type,
    const content_settings::ResourceIdentifier& identifier,
    bool incognito) const {
  ScopedVector<RuleIterator> iterators;
  ExtensionEntryMap::const_reverse_iterator entry;

  scoped_ptr<base::AutoLock> auto_lock(new base::AutoLock(lock_));

  for (entry = entries_.rbegin(); entry != entries_.rend(); ++entry) {
    if (!entry->second->enabled)
      continue;

    if (incognito) {
      iterators.push_back(
          entry->second->incognito_session_only_settings.GetRuleIterator(
              type,
              identifier,
              NULL));
      iterators.push_back(
          entry->second->incognito_persistent_settings.GetRuleIterator(
              type,
              identifier,
              NULL));
    } else {
      iterators.push_back(
          entry->second->settings.GetRuleIterator(type, identifier, NULL));
    }
  }
  return new ConcatenationIterator(&iterators, auto_lock.release());
}


base::ListValue* ContentSettingsStore::GetSettingsForExtension(
    const std::string& extension_id,
    ExtensionPrefsScope scope) const {
  base::AutoLock lock(lock_);
  const OriginIdentifierValueMap* map = GetValueMap(extension_id, scope);
  if (!map)
    return NULL;
  base::ListValue* settings = new base::ListValue();
  OriginIdentifierValueMap::EntryMap::const_iterator it;
  for (it = map->begin(); it != map->end(); ++it) {
    scoped_ptr<RuleIterator> rule_iterator(
        map->GetRuleIterator(it->first.content_type,
                             it->first.resource_identifier,
                             NULL));  // We already hold the lock.
    while (rule_iterator->HasNext()) {
      const Rule& rule = rule_iterator->Next();
      base::DictionaryValue* setting_dict = new base::DictionaryValue();
      setting_dict->SetString(keys::kPrimaryPatternKey,
                              rule.primary_pattern.ToString());
      setting_dict->SetString(keys::kSecondaryPatternKey,
                              rule.secondary_pattern.ToString());
      setting_dict->SetString(
          keys::kContentSettingsTypeKey,
          helpers::ContentSettingsTypeToString(it->first.content_type));
      setting_dict->SetString(keys::kResourceIdentifierKey,
                              it->first.resource_identifier);
      ContentSetting content_setting = ValueToContentSetting(rule.value.get());
      DCHECK_NE(CONTENT_SETTING_DEFAULT, content_setting);
      setting_dict->SetString(
          keys::kContentSettingKey,
          helpers::ContentSettingToString(content_setting));
      settings->Append(setting_dict);
    }
  }
  return settings;
}


OriginIdentifierValueMap* ContentSettingsStore::GetValueMap(
    const std::string& ext_id,
    ExtensionPrefsScope scope) {
  ExtensionEntryMap::const_iterator i = FindEntry(ext_id);
  if (i != entries_.end()) {
    switch (scope) {
      case kExtensionPrefsScopeRegular:
        return &(i->second->settings);
      case kExtensionPrefsScopeRegularOnly:
        NOTREACHED();
        return NULL;
      case kExtensionPrefsScopeIncognitoPersistent:
        return &(i->second->incognito_persistent_settings);
      case kExtensionPrefsScopeIncognitoSessionOnly:
        return &(i->second->incognito_session_only_settings);
    }
  }
  return NULL;
}


const OriginIdentifierValueMap* ContentSettingsStore::GetValueMap(
    const std::string& ext_id,
    ExtensionPrefsScope scope) const {
  ExtensionEntryMap::const_iterator i = FindEntry(ext_id);
  if (i == entries_.end())
    return NULL;

  switch (scope) {
    case kExtensionPrefsScopeRegular:
      return &(i->second->settings);
    case kExtensionPrefsScopeRegularOnly:
      NOTREACHED();
      return NULL;
    case kExtensionPrefsScopeIncognitoPersistent:
      return &(i->second->incognito_persistent_settings);
    case kExtensionPrefsScopeIncognitoSessionOnly:
      return &(i->second->incognito_session_only_settings);
  }

  NOTREACHED();
  return NULL;
}


void ContentSettingsStore::NotifyOfContentSettingChanged(
    const std::string& extension_id,
    bool incognito) {
  FOR_EACH_OBSERVER(
      ContentSettingsStore::Observer,
      observers_,
      OnContentSettingChanged(extension_id, incognito));
}


bool ContentSettingsStore::OnCorrectThread() {
  return !BrowserThread::IsWellKnownThread(BrowserThread::UI) ||
         BrowserThread::CurrentlyOn(BrowserThread::UI);
}


void ContentSettingsStore::RegisterExtension(
    const std::string& ext_id,
    const base::Time& install_time,
    bool is_enabled) {
  base::AutoLock lock(lock_);
  ExtensionEntryMap::iterator i = FindEntry(ext_id);
  if (i != entries_.end()) {
    delete i->second;
    entries_.erase(i);
  }

  ExtensionEntry* entry = new ExtensionEntry;
  entry->id = ext_id;
  entry->enabled = is_enabled;
  entries_.insert(std::make_pair(install_time, entry));
}


void ContentSettingsStore::RemoveObserver(Observer* observer) {
  DCHECK(OnCorrectThread());
  observers_.RemoveObserver(observer);
}


void ContentSettingsStore::SetExtensionContentSetting(
    const std::string& ext_id,
    const ContentSettingsPattern& primary_pattern,
    const ContentSettingsPattern& secondary_pattern,
    ContentSettingsType type,
    const content_settings::ResourceIdentifier& identifier,
    ContentSetting setting,
    ExtensionPrefsScope scope) {
  {
    base::AutoLock lock(lock_);
    OriginIdentifierValueMap* map = GetValueMap(ext_id, scope);
    if (setting == CONTENT_SETTING_DEFAULT) {
      map->DeleteValue(primary_pattern, secondary_pattern, type, identifier);
    } else {
      map->SetValue(primary_pattern, secondary_pattern, type, identifier,
                    base::Value::CreateIntegerValue(setting));
    }
  }

  NotifyOfContentSettingChanged(ext_id,
                                scope != kExtensionPrefsScopeRegular);
}


void ContentSettingsStore::SetExtensionContentSettingFromList(
    const std::string& extension_id,
    const base::ListValue* list,
    ExtensionPrefsScope scope) {
  for (base::ListValue::const_iterator it = list->begin();
       it != list->end(); ++it) {
    if ((*it)->GetType() != Value::TYPE_DICTIONARY) {
      NOTREACHED();
      continue;
    }
    base::DictionaryValue* dict = static_cast<base::DictionaryValue*>(*it);
    std::string primary_pattern_str;
    dict->GetString(keys::kPrimaryPatternKey, &primary_pattern_str);
    ContentSettingsPattern primary_pattern =
        ContentSettingsPattern::FromString(primary_pattern_str);
    DCHECK(primary_pattern.IsValid());

    std::string secondary_pattern_str;
    dict->GetString(keys::kSecondaryPatternKey, &secondary_pattern_str);
    ContentSettingsPattern secondary_pattern =
        ContentSettingsPattern::FromString(secondary_pattern_str);
    DCHECK(secondary_pattern.IsValid());

    std::string content_settings_type_str;
    dict->GetString(keys::kContentSettingsTypeKey, &content_settings_type_str);
    ContentSettingsType content_settings_type =
        helpers::StringToContentSettingsType(content_settings_type_str);
    DCHECK_NE(CONTENT_SETTINGS_TYPE_DEFAULT, content_settings_type);

    std::string resource_identifier;
    dict->GetString(keys::kResourceIdentifierKey, &resource_identifier);

    std::string content_setting_string;
    dict->GetString(keys::kContentSettingKey, &content_setting_string);
    ContentSetting setting = CONTENT_SETTING_DEFAULT;
    bool result =
        helpers::StringToContentSetting(content_setting_string, &setting);
    DCHECK(result);

    SetExtensionContentSetting(extension_id,
                               primary_pattern,
                               secondary_pattern,
                               content_settings_type,
                               resource_identifier,
                               setting,
                               scope);
  }
}


void ContentSettingsStore::SetExtensionState(
    const std::string& ext_id, bool is_enabled) {
  bool notify = false;
  bool notify_incognito = false;
  {
    base::AutoLock lock(lock_);
    ExtensionEntryMap::const_iterator i = FindEntry(ext_id);
    if (i == entries_.end())
      return;
    notify = !i->second->settings.empty();
    notify_incognito = !i->second->incognito_persistent_settings.empty() ||
                       !i->second->incognito_session_only_settings.empty();

    i->second->enabled = is_enabled;
  }
  if (notify)
    NotifyOfContentSettingChanged(ext_id, false);
  if (notify_incognito)
    NotifyOfContentSettingChanged(ext_id, true);
}


void ContentSettingsStore::UnregisterExtension(
    const std::string& ext_id) {
  bool notify = false;
  bool notify_incognito = false;
  {
    base::AutoLock lock(lock_);
    ExtensionEntryMap::iterator i = FindEntry(ext_id);
    if (i == entries_.end())
      return;
    notify = !i->second->settings.empty();
    notify_incognito = !i->second->incognito_persistent_settings.empty() ||
                       !i->second->incognito_session_only_settings.empty();

    delete i->second;
    entries_.erase(i);
  }
  if (notify)
    NotifyOfContentSettingChanged(ext_id, false);
  if (notify_incognito)
    NotifyOfContentSettingChanged(ext_id, true);
}


ContentSettingsStore::~ContentSettingsStore() {
  STLDeleteValues(&entries_);
}


bool AudioManagerBase::CanShowAudioInputSettings() {
  return false;
}


void AudioManagerBase::DecreaseActiveInputStreamCount() {
  DCHECK(IsRecordingInProcess());
  base::AtomicRefCountDec(&num_active_input_streams_);
}


void AudioManagerBase::GetAudioInputDeviceNames(
    media::AudioDeviceNames* device_names) {
}


scoped_refptr<base::MessageLoopProxy> AudioManagerBase::GetMessageLoop() {
  base::AutoLock lock(audio_thread_lock_);
  return audio_thread_.get() ? audio_thread_->message_loop_proxy() : NULL;
}


void AudioManagerBase::IncreaseActiveInputStreamCount() {
  base::AtomicRefCountInc(&num_active_input_streams_);
}


void AudioManagerBase::Init() {
  base::AutoLock lock(audio_thread_lock_);
  DCHECK(!audio_thread_.get());
  audio_thread_.reset(new base::Thread("AudioThread"));
  CHECK(audio_thread_->Start());
}


bool AudioManagerBase::IsRecordingInProcess() {
  return !base::AtomicRefCountIsZero(&num_active_input_streams_);
}


AudioInputStream* AudioManagerBase::MakeAudioInputStream(
    const AudioParameters& params, const std::string& device_id) {
  if (!params.IsValid() || (params.channels() > kMaxInputChannels) ||
      device_id.empty()) {
    DLOG(ERROR) << "Audio parameters are invalid for device " << device_id;
    return NULL;
  }

  if (num_input_streams_ >= max_num_input_streams_) {
    DLOG(ERROR) << "Number of opened input audio streams "
                << num_input_streams_
                << " exceed the max allowed number " << max_num_input_streams_;
    return NULL;
  }

  AudioInputStream* stream = NULL;
  if (params.format() == AudioParameters::AUDIO_MOCK) {
    stream = FakeAudioInputStream::MakeFakeStream(this, params);
  } else if (params.format() == AudioParameters::AUDIO_PCM_LINEAR) {
    stream = MakeLinearInputStream(params, device_id);
  } else if (params.format() == AudioParameters::AUDIO_PCM_LOW_LATENCY) {
    stream = MakeLowLatencyInputStream(params, device_id);
  }

  if (stream)
    ++num_input_streams_;

  return stream;
}


AudioOutputStream* AudioManagerBase::MakeAudioOutputStream(
    const AudioParameters& params) {
  if (!params.IsValid()) {
    DLOG(ERROR) << "Audio parameters are invalid";
    return NULL;
  }

  if (num_output_streams_ >= max_num_output_streams_) {
    DLOG(ERROR) << "Number of opened output audio streams "
                << num_output_streams_
                << " exceed the max allowed number "
                << max_num_output_streams_;
    return NULL;
  }

  AudioOutputStream* stream = NULL;
  if (params.format() == AudioParameters::AUDIO_MOCK) {
    stream = FakeAudioOutputStream::MakeFakeStream(this, params);
  } else if (params.format() == AudioParameters::AUDIO_PCM_LINEAR) {
    stream = MakeLinearOutputStream(params);
  } else if (params.format() == AudioParameters::AUDIO_PCM_LOW_LATENCY) {
    stream = MakeLowLatencyOutputStream(params);
  }

  if (stream)
    ++num_output_streams_;

  return stream;
}


void AudioManagerBase::ReleaseOutputStream(AudioOutputStream* stream) {
  DCHECK(stream);
  num_output_streams_--;
  delete stream;
}


void AudioManagerBase::ShowAudioInputSettings() {
}


void AudioManagerBase::Shutdown() {
  scoped_ptr<base::Thread> audio_thread;
  {
    base::AutoLock lock(audio_thread_lock_);
    audio_thread_.swap(audio_thread);
  }

  if (!audio_thread.get())
    return;

  CHECK_NE(MessageLoop::current(), audio_thread->message_loop());

  audio_thread->message_loop()->PostTask(FROM_HERE, base::Bind(
      &AudioManagerBase::ShutdownOnAudioThread,
      base::Unretained(this)));

  audio_thread->Stop();
}


void AudioManagerBase::ShutdownOnAudioThread() {
  AudioOutputDispatchersMap::iterator it = output_dispatchers_.begin();
  for (; it != output_dispatchers_.end(); ++it) {
    scoped_refptr<AudioOutputDispatcher>& dispatcher = (*it).second;
    if (dispatcher) {
      dispatcher->Shutdown();
      DCHECK(dispatcher->HasOneRef()) << "AudioOutputProxies are still alive";
      dispatcher = NULL;
    }
  }

  output_dispatchers_.clear();
}


AudioManagerBase::~AudioManagerBase() {
  CHECK(!audio_thread_.get());
  DCHECK_EQ(0, num_output_streams_);
  DCHECK_EQ(0, num_input_streams_);
}


  void AssociateRendererProcessToWorker(EmbeddedWorkerInstance* worker) {
    worker->AddProcessReference(
        shell()->web_contents()->GetRenderProcessHost()->GetID());
  }


  EmbeddedWorkerBrowserTest()
      : last_worker_status_(EmbeddedWorkerInstance::STOPPED) {}


void RunAndQuit(const base::Closure& closure,
                const base::Closure& quit,
                base::MessageLoopProxy* original_message_loop) {
  closure.Run();
  original_message_loop->PostTask(FROM_HERE, quit);
}


void RunOnIOThread(const base::Closure& closure) {
  base::RunLoop run_loop;
  BrowserThread::PostTask(
      BrowserThread::IO, FROM_HERE,
      base::Bind(&RunAndQuit, closure, run_loop.QuitClosure(),
                 base::MessageLoopProxy::current()));
  run_loop.Run();
}


ServiceWorkerVersionBrowserTest() : next_registration_id_(1) {}


   void SetUpRegistrationOnIOThread(const std::string& worker_url) {
     const int64 version_id = 1L;
     registration_ = new ServiceWorkerRegistration(
        embedded_test_server()->GetURL("/*"),
        embedded_test_server()->GetURL(worker_url),
        next_registration_id_++);
    version_ = new ServiceWorkerVersion(
        registration_,
        wrapper()->context()->embedded_worker_registry(),
        version_id);
    AssociateRendererProcessToWorker(version_->embedded_worker());
  }


  void StartOnIOThread() {
    ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO));
    worker_ = wrapper()->context()->embedded_worker_registry()->CreateWorker();
    EXPECT_EQ(EmbeddedWorkerInstance::STOPPED, worker_->status());
    worker_->AddObserver(this);

    AssociateRendererProcessToWorker(worker_.get());

    const int64 service_worker_version_id = 33L;
    const GURL script_url = embedded_test_server()->GetURL(
        "/service_worker/worker.js");
    ServiceWorkerStatusCode status = worker_->Start(
        service_worker_version_id, script_url);

    last_worker_status_ = worker_->status();
    EXPECT_EQ(SERVICE_WORKER_OK, status);
    EXPECT_EQ(EmbeddedWorkerInstance::STARTING, last_worker_status_);

    if (status != SERVICE_WORKER_OK && !done_closure_.is_null())
      done_closure_.Run();
  }


  void StopOnIOThread() {
    ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO));
    EXPECT_EQ(EmbeddedWorkerInstance::RUNNING, worker_->status());

    ServiceWorkerStatusCode status = worker_->Stop();

    last_worker_status_ = worker_->status();
    EXPECT_EQ(SERVICE_WORKER_OK, status);
    EXPECT_EQ(EmbeddedWorkerInstance::STOPPING, last_worker_status_);

    if (status != SERVICE_WORKER_OK && !done_closure_.is_null())
      done_closure_.Run();
  }


  void StopOnIOThread(const base::Closure& done,
                      ServiceWorkerStatusCode* result) {
    ASSERT_TRUE(version_);
    version_->StopWorker(CreateReceiver(BrowserThread::UI, done, result));
  }


void CallWorkerContextDestroyedOnMainThread(int embedded_worker_id) {
  if (!RenderThreadImpl::current() ||
      !RenderThreadImpl::current()->embedded_worker_dispatcher())
    return;
  RenderThreadImpl::current()->embedded_worker_dispatcher()->
      WorkerContextDestroyed(embedded_worker_id);
}


EmbeddedWorkerContextClient::EmbeddedWorkerContextClient(
    int embedded_worker_id,
    int64 service_worker_version_id,
    const GURL& script_url)
    : embedded_worker_id_(embedded_worker_id),
      service_worker_version_id_(service_worker_version_id),
      script_url_(script_url),
      sender_(ChildThread::current()->thread_safe_sender()),
      main_thread_proxy_(base::MessageLoopProxy::current()),
      weak_factory_(this) {
  g_worker_client_tls.Pointer()->Set(this);
}


 void EmbeddedWorkerContextClient::OnSendMessageToWorker(
     int thread_id,
     int embedded_worker_id,
    int request_id,
    const IPC::Message& message) {
  if (!script_context_)
    return;
  DCHECK_EQ(embedded_worker_id_, embedded_worker_id);
  script_context_->OnMessageReceived(request_id, message);
}


void EmbeddedWorkerContextClient::SendWorkerStarted() {
  DCHECK(worker_task_runner_->RunsTasksOnCurrentThread());
  sender_->Send(new EmbeddedWorkerHostMsg_WorkerStarted(
      WorkerTaskRunner::Instance()->CurrentWorkerId(),
      embedded_worker_id_));
}


EmbeddedWorkerContextClient::ThreadSpecificInstance() {
  return g_worker_client_tls.Pointer()->Get();
}


void EmbeddedWorkerContextClient::workerContextDestroyed() {
  script_context_.reset();
  main_thread_proxy_->PostTask(
      FROM_HERE,
      base::Bind(&CallWorkerContextDestroyedOnMainThread,
                  embedded_worker_id_));
 }


void EmbeddedWorkerContextClient::workerContextFailedToStart() {
  DCHECK(main_thread_proxy_->RunsTasksOnCurrentThread());
  DCHECK(!script_context_);

  RenderThreadImpl::current()->embedded_worker_dispatcher()->
      WorkerContextDestroyed(embedded_worker_id_);
}


void EmbeddedWorkerContextClient::workerContextStarted(
    blink::WebServiceWorkerContextProxy* proxy) {
  DCHECK(!worker_task_runner_);
  worker_task_runner_ = new WorkerThreadTaskRunner(
      WorkerTaskRunner::Instance()->CurrentWorkerId());
  DCHECK_NE(0, WorkerTaskRunner::Instance()->CurrentWorkerId());
  DCHECK(g_worker_client_tls.Pointer()->Get() == NULL);
  DCHECK(!script_context_);
  g_worker_client_tls.Pointer()->Set(this);
  script_context_.reset(new ServiceWorkerScriptContext(this, proxy));

  worker_task_runner_->PostTask(
      FROM_HERE,
      base::Bind(&EmbeddedWorkerContextClient::SendWorkerStarted,
                 weak_factory_.GetWeakPtr()));
}


EmbeddedWorkerContextClient::~EmbeddedWorkerContextClient() {
  DCHECK(g_worker_client_tls.Pointer()->Get() != NULL);
  g_worker_client_tls.Pointer()->Set(NULL);
}


void ServiceWorkerScriptContext::DidHandleInstallEvent(int request_id) {
  Send(request_id, ServiceWorkerHostMsg_InstallEventFinished());
}


 void ServiceWorkerScriptContext::OnFetchEvent(
    const ServiceWorkerFetchRequest& request) {
  NOTIMPLEMENTED();
}


void ServiceWorkerScriptContext::OnMessageReceived(
    int request_id,
    const IPC::Message& message) {
  DCHECK_EQ(kInvalidRequestId, current_request_id_);
  current_request_id_ = request_id;
  bool handled = true;
  IPC_BEGIN_MESSAGE_MAP(ServiceWorkerScriptContext, message)
    IPC_MESSAGE_HANDLER(ServiceWorkerMsg_InstallEvent, OnInstallEvent)
    IPC_MESSAGE_HANDLER(ServiceWorkerMsg_FetchEvent, OnFetchEvent)
    IPC_MESSAGE_UNHANDLED(handled = false)
  IPC_END_MESSAGE_MAP()
  DCHECK(handled);
  current_request_id_ = kInvalidRequestId;
}


SpeechSynthesis::SpeechSynthesis(ExecutionContext* context)
    : ContextLifecycleObserver(context)
    , m_platformSpeechSynthesizer(PlatformSpeechSynthesizer::create(this))
    , m_isPaused(false)
{
    ScriptWrappable::init(this);
}


void SpeechSynthesis::boundaryEventOccurred(PassRefPtr<PlatformSpeechSynthesisUtterance> utterance, SpeechBoundary boundary, unsigned charIndex)
{
    DEFINE_STATIC_LOCAL(const String, wordBoundaryString, ("word"));
    DEFINE_STATIC_LOCAL(const String, sentenceBoundaryString, ("sentence"));

    switch (boundary) {
    case SpeechWordBoundary:
        fireEvent(EventTypeNames::boundary, static_cast<SpeechSynthesisUtterance*>(utterance->client()), charIndex, wordBoundaryString);
        break;
    case SpeechSentenceBoundary:
        fireEvent(EventTypeNames::boundary, static_cast<SpeechSynthesisUtterance*>(utterance->client()), charIndex, sentenceBoundaryString);
        break;
    default:
        ASSERT_NOT_REACHED();
    }
}


void SpeechSynthesis::cancel()
{
    m_utteranceQueue.clear();
    m_platformSpeechSynthesizer->cancel();
}


PassRefPtrWillBeRawPtr<SpeechSynthesis> SpeechSynthesis::create(ExecutionContext* context)
{
    return adoptRefWillBeRefCountedGarbageCollected(new SpeechSynthesis(context));
}


SpeechSynthesisUtterance* SpeechSynthesis::currentSpeechUtterance() const
{
    if (!m_utteranceQueue.isEmpty())
        return m_utteranceQueue.first().get();
    return 0;
}


void SpeechSynthesis::didFinishSpeaking(PassRefPtr<PlatformSpeechSynthesisUtterance> utterance)
{
    if (utterance->client())
        handleSpeakingCompleted(static_cast<SpeechSynthesisUtterance*>(utterance->client()), false);
}


void SpeechSynthesis::didResumeSpeaking(PassRefPtr<PlatformSpeechSynthesisUtterance> utterance)
{
    m_isPaused = false;
    if (utterance->client())
        fireEvent(EventTypeNames::resume, static_cast<SpeechSynthesisUtterance*>(utterance->client()), 0, String());
}


void SpeechSynthesis::didStartSpeaking(PassRefPtr<PlatformSpeechSynthesisUtterance> utterance)
{
    if (utterance->client())
        fireEvent(EventTypeNames::start, static_cast<SpeechSynthesisUtterance*>(utterance->client()), 0, String());
}


ExecutionContext* SpeechSynthesis::executionContext() const
{
    return ContextLifecycleObserver::executionContext();
}