Commit message: None
CVE: None
Vulnerability description: None

Project: Chrome

gfx::Rect OverlayWindowViews::CalculateAndUpdateWindowBounds() {
  gfx::Rect work_area =
      display::Screen::GetScreen()
          ->GetDisplayNearestWindow(
              controller_->GetInitiatorWebContents()->GetTopLevelNativeWindow())
          .work_area();

  max_size_ = gfx::Size(work_area.width() / 2, work_area.height() / 2);

  min_size_ = kMinWindowSize;

  gfx::Size window_size = window_bounds_.size();
  if (!has_been_shown_) {
    window_size = gfx::Size(work_area.width() / 5, work_area.height() / 5);
    window_size.set_width(std::min(
        max_size_.width(), std::max(min_size_.width(), window_size.width())));
    window_size.set_height(
        std::min(max_size_.height(),
                 std::max(min_size_.height(), window_size.height())));
  }

  if (!window_size.IsEmpty() && !natural_size_.IsEmpty()) {
    float aspect_ratio = (float)natural_size_.width() / natural_size_.height();

    gfx::Rect window_rect(GetBounds().origin(), window_size);
    views::WindowResizeUtils::SizeRectToAspectRatio(
        views::HitTest::kBottomRight, aspect_ratio, min_size_, max_size_,
        &window_rect);
    window_size.SetSize(window_rect.width(), window_rect.height());

    UpdateLayerBoundsWithLetterboxing(window_size);
  }

  gfx::Point origin = window_bounds_.origin();

  int window_diff_width = work_area.right() - window_size.width();
  int window_diff_height = work_area.bottom() - window_size.height();

  int buffer = (window_diff_width + window_diff_height) / 2 * 0.02;

  gfx::Point default_origin =
      gfx::Point(window_diff_width - buffer, window_diff_height - buffer);

  if (has_been_shown_) {
    origin.SetToMin(default_origin);
  } else {
    origin = default_origin;
  }

  window_bounds_ = gfx::Rect(origin, window_size);
  return window_bounds_;
}

Project: Chrome

gfx::Rect OverlayWindowViews::CalculateControlsBounds(int x,
                                                      const gfx::Size& size) {
  return gfx::Rect(
      gfx::Point(x, (GetBounds().size().height() - size.height()) / 2), size);
}

Project: Chrome

void OverlayWindowViews::Close() {
  views::Widget::Close();
}

Project: Chrome

std::unique_ptr<content::OverlayWindow> content::OverlayWindow::Create(
    content::PictureInPictureWindowController* controller) {
  return base::WrapUnique(new OverlayWindowViews(controller));
}

Project: Chrome

void OverlayWindowViews::CreateCustomControl(
    std::unique_ptr<views::ControlImageButton>& control_button,
    const blink::PictureInPictureControlInfo& info,
    ControlPosition position) {
  control_button = std::make_unique<views::ControlImageButton>(this);
  controls_parent_view_->AddChildView(control_button.get());
  control_button->set_id(info.id);
  control_button->set_owned_by_client();

  control_button->SetImageAlignment(views::ImageButton::ALIGN_CENTER,
                                    views::ImageButton::ALIGN_MIDDLE);
  UpdateCustomControlsSize(control_button.get());
  UpdateControlsBounds();

  base::string16 custom_button_label = base::UTF8ToUTF16(info.label);
  control_button->SetAccessibleName(custom_button_label);
  control_button->SetTooltipText(custom_button_label);
  control_button->SetInstallFocusRingOnFocus(true);
  control_button->SetFocusForPlatform();
}

Project: Chrome

gfx::Rect OverlayWindowViews::GetBounds() const {
  return views::Widget::GetRestoredBounds();
}

Project: Chrome

gfx::Rect OverlayWindowViews::GetCloseControlsBounds() {
  return close_controls_view_->GetMirroredBounds();
}

Project: Chrome

ui::Layer* OverlayWindowViews::GetControlsParentLayer() {
  return controls_parent_view_->layer();
}

Project: Chrome

ui::Layer* OverlayWindowViews::GetControlsScrimLayer() {
  return controls_scrim_view_->layer();
}

Project: Chrome

OverlayWindowViews::WindowQuadrant GetCurrentWindowQuadrant(
    const gfx::Rect window_bounds,
    content::PictureInPictureWindowController* controller) {
  gfx::Rect work_area =
      display::Screen::GetScreen()
          ->GetDisplayNearestWindow(
              controller->GetInitiatorWebContents()->GetTopLevelNativeWindow())
          .work_area();
  gfx::Point window_center = window_bounds.CenterPoint();

  if (window_center.x() < work_area.width() / 2) {
    return (window_center.y() < work_area.height() / 2)
               ? OverlayWindowViews::WindowQuadrant::kTopLeft
               : OverlayWindowViews::WindowQuadrant::kBottomLeft;
  }
  return (window_center.y() < work_area.height() / 2)
             ? OverlayWindowViews::WindowQuadrant::kTopRight
             : OverlayWindowViews::WindowQuadrant::kBottomRight;
}

Project: Chrome

gfx::Rect OverlayWindowViews::GetFirstCustomControlsBounds() {
  if (!first_custom_controls_view_)
    return gfx::Rect();
  return first_custom_controls_view_->GetMirroredBounds();
}

Project: Chrome

ui::Layer* OverlayWindowViews::GetLayer() {
  return views::Widget::GetLayer();
}

Project: Chrome

gfx::Size OverlayWindowViews::GetMaximumSize() const {
  return max_size_;
}

Project: Chrome

gfx::Rect OverlayWindowViews::GetPlayPauseControlsBounds() {
  return play_pause_controls_view_->GetMirroredBounds();
}

Project: Chrome

ui::Layer* OverlayWindowViews::GetResizeHandleLayer() {
  return resize_handle_view_->layer();
}

Project: Chrome

gfx::Rect OverlayWindowViews::GetSecondCustomControlsBounds() {
  if (!second_custom_controls_view_)
    return gfx::Rect();
  return second_custom_controls_view_->GetMirroredBounds();
}

Project: Chrome

gfx::Rect OverlayWindowViews::GetVideoBounds() {
  return video_bounds_;
}

Project: Chrome

ui::Layer* OverlayWindowViews::GetVideoLayer() {
  return video_view_->layer();
}

Project: Chrome

ui::Layer* OverlayWindowViews::GetWindowBackgroundLayer() {
  return window_background_view_->layer();
}

Project: Chrome

bool OverlayWindowViews::HasOnlyOneCustomControl() {
  return first_custom_controls_view_ && !second_custom_controls_view_;
}

Project: Chrome

void OverlayWindowViews::Hide() {
  views::Widget::Hide();
}

Project: Chrome

bool OverlayWindowViews::IsActive() const {
  return views::Widget::IsActive();
}

Project: Chrome

bool OverlayWindowViews::IsAlwaysOnTop() const {
  return true;
}

Project: Chrome

bool OverlayWindowViews::IsVisible() const {
  return views::Widget::IsVisible();
}

Project: Chrome

void OverlayWindowViews::OnKeyEvent(ui::KeyEvent* event) {
  hide_controls_timer_.Reset();

  if (event->type() == ui::ET_KEY_PRESSED ||
      event->key_code() == ui::VKEY_TAB) {
    UpdateControlsVisibility(true);
  }

#if defined(OS_MACOSX)
  if (event->type() == ui::ET_KEY_PRESSED &&
      event->key_code() == ui::VKEY_SPACE) {
    TogglePlayPause();
    event->SetHandled();
  }
#endif  // OS_MACOSX

#if defined(OS_WIN)
  if (event->type() == ui::ET_KEY_PRESSED && event->IsAltDown() &&
      event->key_code() == ui::VKEY_F4) {
    controller_->Close(true /* should_pause_video */,
                       true /* should_reset_pip_player */);
    event->SetHandled();
  }
#endif  // OS_WIN

  views::Widget::OnKeyEvent(event);
}

Project: Chrome

void OverlayWindowViews::OnNativeBlur() {
  if (is_initialized_)
    UpdateControlsVisibility(false);

  views::Widget::OnNativeBlur();
}

Project: Chrome

void OverlayWindowViews::OnNativeWidgetDestroyed() {
  controller_->OnWindowDestroyed();
}

Project: Chrome

void OverlayWindowViews::OnNativeWidgetMove() {
  if (is_initialized_)
    UpdateControlsVisibility(false);

  window_bounds_ = GetBounds();

#if defined(OS_CHROMEOS)
  WindowQuadrant quadrant = GetCurrentWindowQuadrant(GetBounds(), controller_);
  close_controls_view_->SetPosition(GetBounds().size(), quadrant);
  resize_handle_view_->SetPosition(GetBounds().size(), quadrant);
#endif
}

Project: Chrome

void OverlayWindowViews::OnNativeWidgetWorkspaceChanged() {
}

Project: Chrome

  explicit OverlayWindowFrameView(views::Widget* widget) : widget_(widget) {}

Project: Chrome

  explicit OverlayWindowWidgetDelegate(views::Widget* widget)
      : widget_(widget) {
    DCHECK(widget_);
  }

Project: Chrome

void OverlayWindowViews::SetAlwaysHidePlayPauseButton(bool is_visible) {
  always_hide_play_pause_button_ = !is_visible;
}

Project: Chrome

void OverlayWindowViews::SetPictureInPictureCustomControls(
    const std::vector<blink::PictureInPictureControlInfo>& controls) {
  first_custom_controls_view_.reset();
  second_custom_controls_view_.reset();

  if (controls.size() > 0)
    CreateCustomControl(first_custom_controls_view_, controls[0],
                        ControlPosition::kLeft);
  if (controls.size() > 1)
    CreateCustomControl(second_custom_controls_view_, controls[1],
                        ControlPosition::kRight);
}

Project: Chrome

void OverlayWindowViews::SetPlaybackState(PlaybackState playback_state) {
  bool controls_parent_layer_visible = GetControlsParentLayer()->visible();

  playback_state_ = playback_state;

  switch (playback_state_) {
    case kPlaying:
      play_pause_controls_view_->SetToggled(true);
      controls_parent_view_->SetVisible(true);
      video_view_->SetVisible(true);
      GetControlsParentLayer()->SetVisible(controls_parent_layer_visible);
      break;
    case kPaused:
      play_pause_controls_view_->SetToggled(false);
      controls_parent_view_->SetVisible(true);
      video_view_->SetVisible(true);
      GetControlsParentLayer()->SetVisible(controls_parent_layer_visible);
      break;
    case kNoVideo:
      controls_scrim_view_->SetVisible(false);
      controls_parent_view_->SetVisible(false);
      video_view_->SetVisible(false);
      GetControlsParentLayer()->SetVisible(false);
      break;
  }
}

Project: Chrome

void OverlayWindowViews::SetUpViews() {
  gfx::Rect larger_window_bounds = GetBounds();
  larger_window_bounds.Inset(-1, -1);
  window_background_view_->SetSize(larger_window_bounds.size());
  window_background_view_->SetPaintToLayer(ui::LAYER_SOLID_COLOR);
  GetWindowBackgroundLayer()->SetColor(SK_ColorBLACK);

  controls_scrim_view_->SetSize(GetBounds().size());
  controls_scrim_view_->SetPaintToLayer(ui::LAYER_SOLID_COLOR);
  GetControlsScrimLayer()->SetColor(gfx::kGoogleGrey900);
  GetControlsScrimLayer()->SetOpacity(0.43f);

  controls_parent_view_->SetPaintToLayer(ui::LAYER_TEXTURED);
  controls_parent_view_->SetSize(GetBounds().size());
  controls_parent_view_->layer()->SetFillsBoundsOpaquely(false);
  controls_parent_view_->set_owned_by_client();

  close_controls_view_->SetPaintToLayer(ui::LAYER_TEXTURED);
  close_controls_view_->layer()->SetFillsBoundsOpaquely(false);
  close_controls_view_->set_owned_by_client();

  video_view_->SetPaintToLayer(ui::LAYER_TEXTURED);

  play_pause_controls_view_->SetImageAlignment(
      views::ImageButton::ALIGN_CENTER, views::ImageButton::ALIGN_MIDDLE);
  play_pause_controls_view_->SetToggled(controller_->IsPlayerActive());
  play_pause_controls_view_->set_owned_by_client();

#if defined(OS_CHROMEOS)
  resize_handle_view_->SetPaintToLayer(ui::LAYER_TEXTURED);
  resize_handle_view_->layer()->SetFillsBoundsOpaquely(false);
  resize_handle_view_->set_owned_by_client();
#endif

  play_pause_controls_view_->SetFocusForPlatform();  // Make button focusable.
  const base::string16 play_pause_accessible_button_label(
      l10n_util::GetStringUTF16(
          IDS_PICTURE_IN_PICTURE_PLAY_PAUSE_CONTROL_ACCESSIBLE_TEXT));
  play_pause_controls_view_->SetAccessibleName(
      play_pause_accessible_button_label);
  const base::string16 play_button_label(
      l10n_util::GetStringUTF16(IDS_PICTURE_IN_PICTURE_PLAY_CONTROL_TEXT));
  play_pause_controls_view_->SetTooltipText(play_button_label);
  const base::string16 pause_button_label(
      l10n_util::GetStringUTF16(IDS_PICTURE_IN_PICTURE_PAUSE_CONTROL_TEXT));
  play_pause_controls_view_->SetToggledTooltipText(pause_button_label);
  play_pause_controls_view_->SetInstallFocusRingOnFocus(true);

  controls_parent_view_->AddChildView(play_pause_controls_view_.get());
  GetContentsView()->AddChildView(controls_scrim_view_.get());
  GetContentsView()->AddChildView(controls_parent_view_.get());
  GetContentsView()->AddChildView(close_controls_view_.get());
#if defined(OS_CHROMEOS)
  GetContentsView()->AddChildView(resize_handle_view_.get());
#endif

  UpdatePlayPauseControlsSize();
  UpdateControlsVisibility(false);
}

Project: Chrome

void OverlayWindowViews::Show() {
  views::Widget::Show();

  has_been_shown_ = true;
}

Project: Chrome

void OverlayWindowViews::TogglePlayPause() {
  bool is_active = controller_->TogglePlayPause();
  play_pause_controls_view_->SetToggled(is_active);
}

Project: Chrome

void OverlayWindowViews::UpdateButtonSize() {
  const gfx::Size window_size = GetBounds().size();
  int scaled_button_dimension =
      window_size.width() < window_size.height()
          ? window_size.width() * kControlRatioToWindow
          : window_size.height() * kControlRatioToWindow;

  int new_button_dimension =
      std::max(kMinControlButtonSize, scaled_button_dimension);

  button_size_.SetSize(new_button_dimension, new_button_dimension);
}

Project: Chrome

void OverlayWindowViews::UpdateControlsBounds() {
  gfx::Rect larger_window_bounds = GetBounds();
  larger_window_bounds.Inset(-1, -1);
  controls_scrim_view_->SetBoundsRect(
      gfx::Rect(gfx::Point(0, 0), larger_window_bounds.size()));

  WindowQuadrant quadrant = GetCurrentWindowQuadrant(GetBounds(), controller_);
  close_controls_view_->SetPosition(GetBounds().size(), quadrant);
#if defined(OS_CHROMEOS)
  resize_handle_view_->SetPosition(GetBounds().size(), quadrant);
#endif

  controls_parent_view_->SetBoundsRect(
      gfx::Rect(gfx::Point(0, 0), GetBounds().size()));

  UpdateControlsPositions();
}

Project: Chrome

void OverlayWindowViews::UpdateControlsPositions() {
  int mid_window_x = GetBounds().size().width() / 2;

  if (HasOnlyOneCustomControl()) {
    play_pause_controls_view_->SetBoundsRect(
        CalculateControlsBounds(mid_window_x, button_size_));
    first_custom_controls_view_->SetBoundsRect(CalculateControlsBounds(
        mid_window_x - button_size_.width(), button_size_));
    return;
  }

  play_pause_controls_view_->SetBoundsRect(CalculateControlsBounds(
      mid_window_x - button_size_.width() / 2, button_size_));

  if (first_custom_controls_view_ && second_custom_controls_view_) {
    first_custom_controls_view_->SetBoundsRect(CalculateControlsBounds(
        mid_window_x - button_size_.width() / 2 - button_size_.width(),
        button_size_));
    second_custom_controls_view_->SetBoundsRect(CalculateControlsBounds(
        mid_window_x + button_size_.width() / 2, button_size_));
  }
}

Project: Chrome

void OverlayWindowViews::UpdateControlsVisibility(bool is_visible) {
  if (always_hide_play_pause_button_ && is_visible)
    play_pause_controls_view_->SetVisible(false);

  GetCloseControlsLayer()->SetVisible(is_visible);

#if defined(OS_CHROMEOS)
  GetResizeHandleLayer()->SetVisible(is_visible);
#endif

  GetControlsScrimLayer()->SetVisible(
      (playback_state_ == kNoVideo) ? false : is_visible);
  GetControlsParentLayer()->SetVisible(
      (playback_state_ == kNoVideo) ? false : is_visible);
}

Project: Chrome

void OverlayWindowViews::UpdateCustomControlsSize(
    views::ControlImageButton* control_button) {
  if (!control_button)
    return;
  UpdateButtonSize();
  control_button->SetSize(button_size_);
  if (control_button == first_custom_controls_view_.get()) {
    first_custom_controls_view_->SetImage(
        views::Button::STATE_NORMAL,
        gfx::CreateVectorIcon(vector_icons::kPlayArrowIcon,
                              button_size_.width() / 2, kControlIconColor));
  }
  if (control_button == second_custom_controls_view_.get()) {
    second_custom_controls_view_->SetImage(
        views::Button::STATE_NORMAL,
        gfx::CreateVectorIcon(vector_icons::kPauseIcon,
                              button_size_.width() / 2, kControlIconColor));
  }
  const gfx::ImageSkia control_background = gfx::CreateVectorIcon(
      kPictureInPictureControlBackgroundIcon, button_size_.width(), kBgColor);
  control_button->SetBackgroundImage(kBgColor, &control_background,
                                     &control_background);
}

Project: Chrome

void OverlayWindowViews::UpdateLayerBoundsWithLetterboxing(
    gfx::Size window_size) {
  if (window_bounds_.size().IsEmpty() || natural_size_.IsEmpty())
    return;

  gfx::Rect letterbox_region = media::ComputeLetterboxRegion(
      gfx::Rect(gfx::Point(0, 0), window_size), natural_size_);
  if (letterbox_region.IsEmpty())
    return;

  gfx::Size letterbox_size = letterbox_region.size();
  gfx::Point origin =
      gfx::Point((window_size.width() - letterbox_size.width()) / 2,
                 (window_size.height() - letterbox_size.height()) / 2);

  video_bounds_.set_origin(origin);
  video_bounds_.set_size(letterbox_region.size());

  UpdateControlsBounds();

  controller_->UpdateLayerBounds();
}

Project: Chrome

void OverlayWindowViews::UpdatePlayPauseControlsSize() {
  UpdateButtonSize();
  play_pause_controls_view_->SetSize(button_size_);
  play_pause_controls_view_->SetImage(
      views::Button::STATE_NORMAL,
      gfx::CreateVectorIcon(vector_icons::kPlayArrowIcon,
                            button_size_.width() / 2, kControlIconColor));
  gfx::ImageSkia pause_icon = gfx::CreateVectorIcon(
      vector_icons::kPauseIcon, button_size_.width() / 2, kControlIconColor);
  play_pause_controls_view_->SetToggledImage(views::Button::STATE_NORMAL,
                                             &pause_icon);
  const gfx::ImageSkia play_pause_background = gfx::CreateVectorIcon(
      kPictureInPictureControlBackgroundIcon, button_size_.width(), kBgColor);
  play_pause_controls_view_->SetBackgroundImage(
      kBgColor, &play_pause_background, &play_pause_background);
}

Project: Chrome

void OverlayWindowViews::UpdateVideoSize(const gfx::Size& natural_size) {
  DCHECK(!natural_size.IsEmpty());
  natural_size_ = natural_size;
  SetAspectRatio(gfx::SizeF(natural_size_));

  SetBounds(CalculateAndUpdateWindowBounds());
}

Project: Chrome

views::View* OverlayWindowViews::controls_parent_view_for_testing() const {
  return controls_parent_view_.get();
}

Project: Chrome

OverlayWindowViews::play_pause_controls_view_for_testing() const {
  return play_pause_controls_view_.get();
}

Project: Chrome

OverlayWindowViews::playback_state_for_testing() const {
  return playback_state_;
}

Project: Chrome

gfx::Point OverlayWindowViews::resize_handle_position_for_testing() const {
  return resize_handle_view_->origin();
}