普通文本  |  272行  |  7.89 KB

// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "android_webview/browser/shared_renderer_state.h"

#include "android_webview/browser/browser_view_renderer_client.h"
#include "base/bind.h"
#include "base/lazy_instance.h"
#include "base/location.h"

namespace android_webview {

namespace internal {

class RequestDrawGLTracker {
 public:
  RequestDrawGLTracker();
  bool ShouldRequestOnNoneUiThread(SharedRendererState* state);
  bool ShouldRequestOnUiThread(SharedRendererState* state);
  void ResetPending();
  void SetQueuedFunctorOnUi(SharedRendererState* state);

 private:
  base::Lock lock_;
  SharedRendererState* pending_ui_;
  SharedRendererState* pending_non_ui_;
};

RequestDrawGLTracker::RequestDrawGLTracker()
    : pending_ui_(NULL), pending_non_ui_(NULL) {
}

bool RequestDrawGLTracker::ShouldRequestOnNoneUiThread(
    SharedRendererState* state) {
  base::AutoLock lock(lock_);
  if (pending_ui_ || pending_non_ui_)
    return false;
  pending_non_ui_ = state;
  return true;
}

bool RequestDrawGLTracker::ShouldRequestOnUiThread(SharedRendererState* state) {
  base::AutoLock lock(lock_);
  if (pending_non_ui_) {
    pending_non_ui_->ResetRequestDrawGLCallback();
    pending_non_ui_ = NULL;
  }
  // At this time, we could have already called RequestDrawGL on the UI thread,
  // but the corresponding GL mode process hasn't happened yet. In this case,
  // don't schedule another requestDrawGL on the UI thread.
  if (pending_ui_)
    return false;
  pending_ui_ = state;
  return true;
}

void RequestDrawGLTracker::ResetPending() {
  base::AutoLock lock(lock_);
  pending_non_ui_ = NULL;
  pending_ui_ = NULL;
}

void RequestDrawGLTracker::SetQueuedFunctorOnUi(SharedRendererState* state) {
  base::AutoLock lock(lock_);
  DCHECK(state);
  DCHECK(pending_ui_ == state || pending_non_ui_ == state);
  pending_ui_ = state;
  pending_non_ui_ = NULL;
}

}  // namespace internal

namespace {

base::LazyInstance<internal::RequestDrawGLTracker> g_request_draw_gl_tracker =
    LAZY_INSTANCE_INITIALIZER;

}

SharedRendererState::SharedRendererState(
    scoped_refptr<base::MessageLoopProxy> ui_loop,
    BrowserViewRendererClient* client)
    : ui_loop_(ui_loop),
      client_on_ui_(client),
      force_commit_(false),
      inside_hardware_release_(false),
      needs_force_invalidate_on_next_draw_gl_(false),
      weak_factory_on_ui_thread_(this) {
  DCHECK(ui_loop_->BelongsToCurrentThread());
  DCHECK(client_on_ui_);
  ui_thread_weak_ptr_ = weak_factory_on_ui_thread_.GetWeakPtr();
  ResetRequestDrawGLCallback();
}

SharedRendererState::~SharedRendererState() {
  DCHECK(ui_loop_->BelongsToCurrentThread());
}

void SharedRendererState::ClientRequestDrawGL() {
  if (ui_loop_->BelongsToCurrentThread()) {
    if (!g_request_draw_gl_tracker.Get().ShouldRequestOnUiThread(this))
      return;
    ClientRequestDrawGLOnUIThread();
  } else {
    if (!g_request_draw_gl_tracker.Get().ShouldRequestOnNoneUiThread(this))
      return;
    base::Closure callback;
    {
      base::AutoLock lock(lock_);
      callback = request_draw_gl_closure_;
    }
    ui_loop_->PostTask(FROM_HERE, callback);
  }
}

void SharedRendererState::DidDrawGLProcess() {
  g_request_draw_gl_tracker.Get().ResetPending();
}

void SharedRendererState::ResetRequestDrawGLCallback() {
  DCHECK(ui_loop_->BelongsToCurrentThread());
  base::AutoLock lock(lock_);
  request_draw_gl_cancelable_closure_.Reset(
      base::Bind(&SharedRendererState::ClientRequestDrawGLOnUIThread,
                 base::Unretained(this)));
  request_draw_gl_closure_ = request_draw_gl_cancelable_closure_.callback();
}

void SharedRendererState::ClientRequestDrawGLOnUIThread() {
  DCHECK(ui_loop_->BelongsToCurrentThread());
  ResetRequestDrawGLCallback();
  g_request_draw_gl_tracker.Get().SetQueuedFunctorOnUi(this);
  if (!client_on_ui_->RequestDrawGL(NULL, false)) {
    g_request_draw_gl_tracker.Get().ResetPending();
    LOG(ERROR) << "Failed to request GL process. Deadlock likely";
  }
}

void SharedRendererState::UpdateParentDrawConstraintsOnUIThread() {
  DCHECK(ui_loop_->BelongsToCurrentThread());
  client_on_ui_->UpdateParentDrawConstraints();
}

void SharedRendererState::SetScrollOffset(gfx::Vector2d scroll_offset) {
  base::AutoLock lock(lock_);
  scroll_offset_ = scroll_offset;
}

gfx::Vector2d SharedRendererState::GetScrollOffset() {
  base::AutoLock lock(lock_);
  return scroll_offset_;
}

bool SharedRendererState::HasCompositorFrame() const {
  base::AutoLock lock(lock_);
  return compositor_frame_.get();
}

void SharedRendererState::SetCompositorFrame(
    scoped_ptr<cc::CompositorFrame> frame, bool force_commit) {
  base::AutoLock lock(lock_);
  DCHECK(!compositor_frame_.get());
  compositor_frame_ = frame.Pass();
  force_commit_ = force_commit;
}

scoped_ptr<cc::CompositorFrame> SharedRendererState::PassCompositorFrame() {
  base::AutoLock lock(lock_);
  return compositor_frame_.Pass();
}

bool SharedRendererState::ForceCommit() const {
  base::AutoLock lock(lock_);
  return force_commit_;
}

bool SharedRendererState::UpdateDrawConstraints(
    const ParentCompositorDrawConstraints& parent_draw_constraints) {
  base::AutoLock lock(lock_);
  if (needs_force_invalidate_on_next_draw_gl_ ||
      !parent_draw_constraints_.Equals(parent_draw_constraints)) {
    parent_draw_constraints_ = parent_draw_constraints;
    return true;
  }

  return false;
}

void SharedRendererState::PostExternalDrawConstraintsToChildCompositor(
    const ParentCompositorDrawConstraints& parent_draw_constraints) {
  if (UpdateDrawConstraints(parent_draw_constraints)) {
    // No need to hold the lock_ during the post task.
    ui_loop_->PostTask(
        FROM_HERE,
        base::Bind(&SharedRendererState::UpdateParentDrawConstraintsOnUIThread,
                   ui_thread_weak_ptr_));
  }
}

void SharedRendererState::DidSkipCommitFrame() {
  ui_loop_->PostTask(
      FROM_HERE,
      base::Bind(&SharedRendererState::DidSkipCommitFrameOnUIThread,
                 ui_thread_weak_ptr_));
}

void SharedRendererState::DidSkipCommitFrameOnUIThread() {
  DCHECK(ui_loop_->BelongsToCurrentThread());
  client_on_ui_->DidSkipCommitFrame();
}

const ParentCompositorDrawConstraints
SharedRendererState::ParentDrawConstraints() const {
  base::AutoLock lock(lock_);
  return parent_draw_constraints_;
}

void SharedRendererState::SetForceInvalidateOnNextDrawGL(
    bool needs_force_invalidate_on_next_draw_gl) {
  base::AutoLock lock(lock_);
  needs_force_invalidate_on_next_draw_gl_ =
      needs_force_invalidate_on_next_draw_gl;
}

bool SharedRendererState::NeedsForceInvalidateOnNextDrawGL() const {
  base::AutoLock lock(lock_);
  return needs_force_invalidate_on_next_draw_gl_;
}

void SharedRendererState::SetInsideHardwareRelease(bool inside) {
  base::AutoLock lock(lock_);
  inside_hardware_release_ = inside;
}

bool SharedRendererState::IsInsideHardwareRelease() const {
  base::AutoLock lock(lock_);
  return inside_hardware_release_;
}

void SharedRendererState::InsertReturnedResources(
    const cc::ReturnedResourceArray& resources) {
  base::AutoLock lock(lock_);
  returned_resources_.insert(
      returned_resources_.end(), resources.begin(), resources.end());
}

void SharedRendererState::SwapReturnedResources(
    cc::ReturnedResourceArray* resources) {
  DCHECK(resources->empty());
  base::AutoLock lock(lock_);
  resources->swap(returned_resources_);
}

bool SharedRendererState::ReturnedResourcesEmpty() const {
  base::AutoLock lock(lock_);
  return returned_resources_.empty();
}

InsideHardwareReleaseReset::InsideHardwareReleaseReset(
    SharedRendererState* shared_renderer_state)
    : shared_renderer_state_(shared_renderer_state) {
  DCHECK(!shared_renderer_state_->IsInsideHardwareRelease());
  shared_renderer_state_->SetInsideHardwareRelease(true);
}

InsideHardwareReleaseReset::~InsideHardwareReleaseReset() {
  shared_renderer_state_->SetInsideHardwareRelease(false);
}

}  // namespace android_webview