| Index: chrome/browser/android/vr_shell/vr_shell.cc
 | 
| diff --git a/chrome/browser/android/vr_shell/vr_shell.cc b/chrome/browser/android/vr_shell/vr_shell.cc
 | 
| index 6473a6bade186fa9255299078a0af5d8cd7460bd..62c7a1dcbbd5f7719de1f23f088dfb4124892a00 100644
 | 
| --- a/chrome/browser/android/vr_shell/vr_shell.cc
 | 
| +++ b/chrome/browser/android/vr_shell/vr_shell.cc
 | 
| @@ -73,23 +73,6 @@ static constexpr float kReticleDistanceMultiplier = 1.5f;
 | 
|  // UI element 0 is the browser content rectangle.
 | 
|  static constexpr int kBrowserUiElementId = 0;
 | 
|  
 | 
| -// Positions and sizes of statically placed UI elements in the UI texture.
 | 
| -// TODO(klausw): replace the hardcoded positions with JS position/offset
 | 
| -// retrieval once the infrastructure for that is hooked up.
 | 
| -//
 | 
| -// UI is designed with 1 pixel = 1mm at 1m distance. It's rescaled to
 | 
| -// maintain the same angular resolution if placed closer or further.
 | 
| -// The warning overlays should be fairly close since they cut holes
 | 
| -// into geometry (they ignore the Z buffer), leading to odd effects
 | 
| -// if they are far away.
 | 
| -static constexpr vr_shell::Recti kWebVrWarningTransientRect = {
 | 
| -  0, 128, 512, 250};
 | 
| -static constexpr vr_shell::Recti kWebVrWarningPermanentRect = {0, 0, 512, 128};
 | 
| -static constexpr float kWebVrWarningDistance = 0.7f;  // meters
 | 
| -static constexpr float kWebVrWarningPermanentAngle = 16.3f;  // degrees up
 | 
| -// How long the transient warning needs to be displayed.
 | 
| -static constexpr int64_t kWebVrWarningSeconds = 30;
 | 
| -
 | 
|  static constexpr int kFramePrimaryBuffer = 0;
 | 
|  static constexpr int kFrameHeadlockedBuffer = 1;
 | 
|  
 | 
| @@ -444,6 +427,14 @@ void VrShell::DrawFrame(JNIEnv* env, const JavaParamRef<jobject>& obj) {
 | 
|    // Bind the primary framebuffer.
 | 
|    frame.BindBuffer(kFramePrimaryBuffer);
 | 
|  
 | 
| +  HandleQueuedTasks();
 | 
| +
 | 
| +  // Update the render position of all UI elements (including desktop).
 | 
| +  float screen_tilt = desktop_screen_tilt_ * M_PI / 180.0f;
 | 
| +  scene_->UpdateTransforms(screen_tilt, UiScene::TimeInMicroseconds());
 | 
| +
 | 
| +  UpdateController(GetForwardVector(head_pose));
 | 
| +
 | 
|    if (webvr_mode_) {
 | 
|      DrawWebVr();
 | 
|  
 | 
| @@ -458,104 +449,98 @@ void VrShell::DrawFrame(JNIEnv* env, const JavaParamRef<jobject>& obj) {
 | 
|        uint32_t webvr_pose_frame = GetPixelEncodedPoseIndex();
 | 
|        head_pose = webvr_head_pose_[webvr_pose_frame % kPoseRingBufferSize];
 | 
|      }
 | 
| -
 | 
| -    // Wait for the DOM contents to be loaded before rendering to avoid drawing
 | 
| -    // white rectangles with no content.
 | 
| -    if (!webvr_secure_origin_ && IsUiTextureReady()) {
 | 
| -      size_t last_viewport = buffer_viewport_list_->GetSize();
 | 
| -      buffer_viewport_list_->SetBufferViewport(last_viewport++,
 | 
| -          *headlocked_left_viewport_);
 | 
| -      buffer_viewport_list_->SetBufferViewport(last_viewport++,
 | 
| -          *headlocked_right_viewport_);
 | 
| -
 | 
| -      // Bind the headlocked framebuffer.
 | 
| -      frame.BindBuffer(kFrameHeadlockedBuffer);
 | 
| -      DrawWebVrOverlay(target_time.monotonic_system_time_nanos);
 | 
| -    }
 | 
| -  } else {
 | 
| -    DrawVrShell(head_pose);
 | 
|    }
 | 
|  
 | 
| +  DrawVrShell(head_pose, frame);
 | 
| +
 | 
|    frame.Unbind();
 | 
|    frame.Submit(*buffer_viewport_list_, head_pose);
 | 
|  }
 | 
|  
 | 
| -void VrShell::DrawVrShell(const gvr::Mat4f& head_pose) {
 | 
| -  float screen_tilt = desktop_screen_tilt_ * M_PI / 180.0f;
 | 
| -
 | 
| -  HandleQueuedTasks();
 | 
| -
 | 
| -  // Update the render position of all UI elements (including desktop).
 | 
| -  scene_->UpdateTransforms(screen_tilt, UiScene::TimeInMicroseconds());
 | 
| +void VrShell::DrawVrShell(const gvr::Mat4f& head_pose,
 | 
| +                          gvr::Frame &frame) {
 | 
| +  std::vector<const ContentRectangle*> head_locked_elements;
 | 
| +  std::vector<const ContentRectangle*> world_elements;
 | 
| +  for (const auto& rect : scene_->GetUiElements()) {
 | 
| +    if (!rect->visible) {
 | 
| +      continue;
 | 
| +    }
 | 
| +    if (webvr_mode_ && rect->id == kBrowserUiElementId) {
 | 
| +      continue;
 | 
| +    }
 | 
| +    if (rect->lock_to_fov) {
 | 
| +      head_locked_elements.push_back(rect.get());
 | 
| +    } else {
 | 
| +      world_elements.push_back(rect.get());
 | 
| +    }
 | 
| +  }
 | 
|  
 | 
| -  UpdateController(GetForwardVector(head_pose));
 | 
| +  if (!webvr_mode_) {
 | 
| +    glEnable(GL_CULL_FACE);
 | 
| +    glEnable(GL_DEPTH_TEST);
 | 
| +    glEnable(GL_SCISSOR_TEST);
 | 
| +    glClearColor(0.1f, 0.1f, 0.1f, 1.0f);
 | 
| +  }
 | 
|  
 | 
| -  // Use culling to remove back faces.
 | 
| -  glEnable(GL_CULL_FACE);
 | 
| +  if (!world_elements.empty()) {
 | 
| +    DrawUiView(&head_pose, world_elements);
 | 
| +  }
 | 
|  
 | 
| -  // Enable depth testing.
 | 
| -  glEnable(GL_DEPTH_TEST);
 | 
| -  glEnable(GL_SCISSOR_TEST);
 | 
| +  if (!head_locked_elements.empty()) {
 | 
| +    // Switch to head-locked viewports.
 | 
| +    size_t last_viewport = buffer_viewport_list_->GetSize();
 | 
| +    buffer_viewport_list_->SetBufferViewport(last_viewport++,
 | 
| +        *headlocked_left_viewport_);
 | 
| +    buffer_viewport_list_->SetBufferViewport(last_viewport++,
 | 
| +        *headlocked_right_viewport_);
 | 
|  
 | 
| -  glClearColor(0.1f, 0.1f, 0.1f, 1.0f);
 | 
| +    // Bind the headlocked framebuffer.
 | 
| +    frame.BindBuffer(kFrameHeadlockedBuffer);
 | 
| +    glClear(GL_COLOR_BUFFER_BIT);
 | 
|  
 | 
| -  buffer_viewport_list_->GetBufferViewport(GVR_LEFT_EYE,
 | 
| -                                           buffer_viewport_.get());
 | 
| -  DrawEye(GVR_LEFT_EYE, head_pose, *buffer_viewport_);
 | 
| -  buffer_viewport_list_->GetBufferViewport(GVR_RIGHT_EYE,
 | 
| -                                           buffer_viewport_.get());
 | 
| -  DrawEye(GVR_RIGHT_EYE, head_pose, *buffer_viewport_);
 | 
| +    DrawUiView(nullptr, head_locked_elements);
 | 
| +  }
 | 
|  }
 | 
|  
 | 
| -void VrShell::DrawEye(gvr::Eye eye,
 | 
| -                      const gvr::Mat4f& head_pose,
 | 
| -                      const gvr::BufferViewport& params) {
 | 
| -  gvr::Mat4f eye_matrix = gvr_api_->GetEyeFromHeadMatrix(eye);
 | 
| -  gvr::Mat4f view_matrix = MatrixMul(eye_matrix, head_pose);
 | 
| -
 | 
| -  gvr::Recti pixel_rect =
 | 
| -      CalculatePixelSpaceRect(render_size_, params.GetSourceUv());
 | 
| -  glViewport(pixel_rect.left, pixel_rect.bottom,
 | 
| -             pixel_rect.right - pixel_rect.left,
 | 
| -             pixel_rect.top - pixel_rect.bottom);
 | 
| -  glScissor(pixel_rect.left, pixel_rect.bottom,
 | 
| -            pixel_rect.right - pixel_rect.left,
 | 
| -            pixel_rect.top - pixel_rect.bottom);
 | 
| -
 | 
| -  const gvr::Mat4f fov_render_matrix = MatrixMul(
 | 
| -      PerspectiveMatrixFromView(params.GetSourceFov(), kZNear, kZFar),
 | 
| -      eye_matrix);
 | 
| -  const gvr::Mat4f world_render_matrix = MatrixMul(
 | 
| -      PerspectiveMatrixFromView(params.GetSourceFov(), kZNear, kZFar),
 | 
| -      view_matrix);
 | 
| +void VrShell::DrawUiView(const gvr::Mat4f* head_pose,
 | 
| +                         const std::vector<const ContentRectangle*>& elements) {
 | 
| +  for (auto eye : {GVR_LEFT_EYE, GVR_RIGHT_EYE}) {
 | 
| +    buffer_viewport_list_->GetBufferViewport(eye, buffer_viewport_.get());
 | 
|  
 | 
| -  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
 | 
| -
 | 
| -  // TODO(mthiesse): Draw order for transparency.
 | 
| -  DrawUI(world_render_matrix, fov_render_matrix);
 | 
| -  DrawCursor(world_render_matrix);
 | 
| -}
 | 
| +    gvr::Mat4f view_matrix = gvr_api_->GetEyeFromHeadMatrix(eye);
 | 
| +    if (head_pose != nullptr) {
 | 
| +      view_matrix = MatrixMul(view_matrix, *head_pose);
 | 
| +    }
 | 
|  
 | 
| -bool VrShell::IsUiTextureReady() {
 | 
| -  return ui_tex_width_ > 0 && ui_tex_height_ > 0 && dom_contents_loaded_;
 | 
| -}
 | 
| +    gvr::Recti pixel_rect =
 | 
| +        CalculatePixelSpaceRect(render_size_, buffer_viewport_->GetSourceUv());
 | 
| +    glViewport(pixel_rect.left, pixel_rect.bottom,
 | 
| +               pixel_rect.right - pixel_rect.left,
 | 
| +               pixel_rect.top - pixel_rect.bottom);
 | 
| +    glScissor(pixel_rect.left, pixel_rect.bottom,
 | 
| +              pixel_rect.right - pixel_rect.left,
 | 
| +              pixel_rect.top - pixel_rect.bottom);
 | 
| +
 | 
| +    if (!webvr_mode_) {
 | 
| +      glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
 | 
| +    }
 | 
|  
 | 
| -Rectf VrShell::MakeUiGlCopyRect(Recti pixel_rect) {
 | 
| -  CHECK(IsUiTextureReady());
 | 
| -  return Rectf({
 | 
| -      static_cast<float>(pixel_rect.x) / ui_tex_width_,
 | 
| -      static_cast<float>(pixel_rect.y) / ui_tex_height_,
 | 
| -      static_cast<float>(pixel_rect.width) / ui_tex_width_,
 | 
| -      static_cast<float>(pixel_rect.height) / ui_tex_height_});
 | 
| -}
 | 
| +    const gvr::Mat4f render_matrix = MatrixMul(
 | 
| +        PerspectiveMatrixFromView(
 | 
| +            buffer_viewport_->GetSourceFov(), kZNear, kZFar),
 | 
| +        view_matrix);
 | 
|  
 | 
| -void VrShell::DrawUI(const gvr::Mat4f& world_matrix,
 | 
| -                     const gvr::Mat4f& fov_matrix) {
 | 
| -  for (const auto& rect : scene_->GetUiElements()) {
 | 
| -    if (!rect->visible) {
 | 
| -      continue;
 | 
| +    DrawElements(render_matrix, elements);
 | 
| +    if (head_pose != nullptr) {
 | 
| +      DrawCursor(render_matrix);
 | 
|      }
 | 
| +  }
 | 
| +}
 | 
|  
 | 
| +void VrShell::DrawElements(
 | 
| +    const gvr::Mat4f& render_matrix,
 | 
| +    const std::vector<const ContentRectangle*>& elements) {
 | 
| +  for (const auto& rect : elements) {
 | 
|      Rectf copy_rect;
 | 
|      jint texture_handle;
 | 
|      if (rect->id == kBrowserUiElementId) {
 | 
| @@ -570,10 +555,7 @@ void VrShell::DrawUI(const gvr::Mat4f& world_matrix,
 | 
|            ui_tex_height_;
 | 
|        texture_handle = ui_texture_id_;
 | 
|      }
 | 
| -
 | 
| -    const gvr::Mat4f& view_matrix =
 | 
| -        rect->lock_to_fov ? fov_matrix : world_matrix;
 | 
| -    gvr::Mat4f transform = MatrixMul(view_matrix, rect->transform.to_world);
 | 
| +    gvr::Mat4f transform = MatrixMul(render_matrix, rect->transform.to_world);
 | 
|      vr_shell_renderer_->GetTexturedQuadRenderer()->Draw(
 | 
|          texture_handle, transform, copy_rect);
 | 
|    }
 | 
| @@ -669,88 +651,6 @@ void VrShell::DrawWebVr() {
 | 
|    vr_shell_renderer_->GetWebVrRenderer()->Draw(content_texture_id_);
 | 
|  }
 | 
|  
 | 
| -void VrShell::DrawWebVrOverlay(int64_t present_time_nanos) {
 | 
| -  // Draw WebVR security warning overlays for each eye. This uses the
 | 
| -  // eye-from-head matrices but not the pose, goal is to place the icons in an
 | 
| -  // eye-relative position so that they follow along with head rotations.
 | 
| -
 | 
| -  gvr::Mat4f left_eye_view_matrix =
 | 
| -      gvr_api_->GetEyeFromHeadMatrix(GVR_LEFT_EYE);
 | 
| -  gvr::Mat4f right_eye_view_matrix =
 | 
| -      gvr_api_->GetEyeFromHeadMatrix(GVR_RIGHT_EYE);
 | 
| -
 | 
| -  glClear(GL_COLOR_BUFFER_BIT);
 | 
| -
 | 
| -  buffer_viewport_list_->GetBufferViewport(GVR_LEFT_EYE,
 | 
| -                                           buffer_viewport_.get());
 | 
| -  DrawWebVrEye(left_eye_view_matrix, *buffer_viewport_, present_time_nanos);
 | 
| -  buffer_viewport_list_->GetBufferViewport(GVR_RIGHT_EYE,
 | 
| -                                           buffer_viewport_.get());
 | 
| -  DrawWebVrEye(right_eye_view_matrix, *buffer_viewport_, present_time_nanos);
 | 
| -}
 | 
| -
 | 
| -void VrShell::DrawWebVrEye(const gvr::Mat4f& view_matrix,
 | 
| -                           const gvr::BufferViewport& params,
 | 
| -                           int64_t present_time_nanos) {
 | 
| -  gvr::Recti pixel_rect =
 | 
| -      CalculatePixelSpaceRect(render_size_, params.GetSourceUv());
 | 
| -  glViewport(pixel_rect.left, pixel_rect.bottom,
 | 
| -             pixel_rect.right - pixel_rect.left,
 | 
| -             pixel_rect.top - pixel_rect.bottom);
 | 
| -  glScissor(pixel_rect.left, pixel_rect.bottom,
 | 
| -            pixel_rect.right - pixel_rect.left,
 | 
| -            pixel_rect.top - pixel_rect.bottom);
 | 
| -
 | 
| -  gvr::Mat4f projection_matrix =
 | 
| -      PerspectiveMatrixFromView(params.GetSourceFov(), kZNear, kZFar);
 | 
| -
 | 
| -  if (!IsUiTextureReady()) {
 | 
| -    // If the UI texture hasn't been initialized yet, we can't draw the overlay.
 | 
| -    return;
 | 
| -  }
 | 
| -
 | 
| -  // Show IDS_WEBSITE_SETTINGS_INSECURE_WEBVR_CONTENT_PERMANENT text.
 | 
| -  gvr::Mat4f icon_pos;
 | 
| -  SetIdentityM(icon_pos);
 | 
| -  // The UI is designed in pixels with the assumption that 1px = 1mm at 1m
 | 
| -  // distance. Scale mm-to-m and adjust to keep the same angular size if the
 | 
| -  // distance changes.
 | 
| -  const float small_icon_width =
 | 
| -      kWebVrWarningPermanentRect.width / 1000.f * kWebVrWarningDistance;
 | 
| -  const float small_icon_height =
 | 
| -      kWebVrWarningPermanentRect.height / 1000.f * kWebVrWarningDistance;
 | 
| -  const float small_icon_angle =
 | 
| -      kWebVrWarningPermanentAngle * M_PI / 180.f;  // Degrees to radians.
 | 
| -  ScaleM(icon_pos, icon_pos, small_icon_width, small_icon_height, 1.0f);
 | 
| -  TranslateM(icon_pos, icon_pos, 0.0f, 0.0f, -kWebVrWarningDistance);
 | 
| -  icon_pos = MatrixMul(
 | 
| -      QuatToMatrix(QuatFromAxisAngle({1.f, 0.f, 0.f}, small_icon_angle)),
 | 
| -      icon_pos);
 | 
| -  gvr::Mat4f combined = MatrixMul(projection_matrix,
 | 
| -                                  MatrixMul(view_matrix, icon_pos));
 | 
| -  vr_shell_renderer_->GetTexturedQuadRenderer()->Draw(
 | 
| -      ui_texture_id_, combined, MakeUiGlCopyRect(kWebVrWarningPermanentRect));
 | 
| -
 | 
| -  // Check if we also need to show the transient warning.
 | 
| -  if (present_time_nanos > webvr_warning_end_nanos_) {
 | 
| -    return;
 | 
| -  }
 | 
| -
 | 
| -  // Show IDS_WEBSITE_SETTINGS_INSECURE_WEBVR_CONTENT_TRANSIENT text.
 | 
| -  SetIdentityM(icon_pos);
 | 
| -  const float large_icon_width =
 | 
| -      kWebVrWarningTransientRect.width / 1000.f * kWebVrWarningDistance;
 | 
| -  const float large_icon_height =
 | 
| -      kWebVrWarningTransientRect.height / 1000.f * kWebVrWarningDistance;
 | 
| -  ScaleM(icon_pos, icon_pos, large_icon_width, large_icon_height, 1.0f);
 | 
| -  TranslateM(icon_pos, icon_pos, 0.0f, 0.0f, -kWebVrWarningDistance);
 | 
| -  combined = MatrixMul(projection_matrix,
 | 
| -                       MatrixMul(view_matrix, icon_pos));
 | 
| -  vr_shell_renderer_->GetTexturedQuadRenderer()->Draw(
 | 
| -      ui_texture_id_, combined, MakeUiGlCopyRect(kWebVrWarningTransientRect));
 | 
| -
 | 
| -}
 | 
| -
 | 
|  void VrShell::OnTriggerEvent(JNIEnv* env, const JavaParamRef<jobject>& obj) {
 | 
|    // Set a flag to handle this on the render thread at the next frame.
 | 
|    touch_pending_ = true;
 | 
| @@ -800,18 +700,14 @@ void VrShell::SetWebVrMode(JNIEnv* env,
 | 
|                             bool enabled) {
 | 
|    webvr_mode_ = enabled;
 | 
|    if (enabled) {
 | 
| -    int64_t now = gvr::GvrApi::GetTimePointNow().monotonic_system_time_nanos;
 | 
| -    constexpr int64_t seconds_to_nanos = 1000 * 1000 * 1000;
 | 
| -    webvr_warning_end_nanos_ = now + kWebVrWarningSeconds * seconds_to_nanos;
 | 
|      html_interface_->SetMode(UiInterface::Mode::WEB_VR);
 | 
|    } else {
 | 
| -    webvr_warning_end_nanos_ = 0;
 | 
|      html_interface_->SetMode(UiInterface::Mode::STANDARD);
 | 
|    }
 | 
|  }
 | 
|  
 | 
|  void VrShell::SetWebVRSecureOrigin(bool secure_origin) {
 | 
| -  webvr_secure_origin_ = secure_origin;
 | 
| +  html_interface_->SetSecureOrigin(secure_origin);
 | 
|  }
 | 
|  
 | 
|  void VrShell::SubmitWebVRFrame() {
 | 
| 
 |