chromium/components/live_caption/views/caption_bubble.cc

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

#include "components/live_caption/views/caption_bubble.h"

#include <algorithm>
#include <memory>
#include <string>
#include <utility>
#include <vector>

#include "base/feature_list.h"
#include "base/functional/bind.h"
#include "base/i18n/rtl.h"
#include "base/memory/raw_ptr.h"
#include "base/metrics/histogram_functions.h"
#include "base/numerics/safe_conversions.h"
#include "base/time/default_tick_clock.h"
#include "base/time/time.h"
#include "base/timer/timer.h"
#include "build/build_config.h"
#include "components/live_caption/caption_bubble_context.h"
#include "components/live_caption/pref_names.h"
#include "components/prefs/pref_change_registrar.h"
#include "components/prefs/pref_service.h"
#include "components/strings/grit/components_strings.h"
#include "components/vector_icons/vector_icons.h"
#include "media/base/media_switches.h"
#include "third_party/re2/src/re2/re2.h"
#include "ui/accessibility/ax_action_data.h"
#include "ui/accessibility/ax_enums.mojom.h"
#include "ui/accessibility/ax_mode_observer.h"
#include "ui/accessibility/ax_node_data.h"
#include "ui/base/buildflags.h"
#include "ui/base/hit_test.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/metadata/metadata_impl_macros.h"
#include "ui/base/mojom/dialog_button.mojom.h"
#include "ui/color/color_id.h"
#include "ui/compositor/layer.h"
#include "ui/events/event.h"
#include "ui/gfx/animation/slide_animation.h"
#include "ui/gfx/geometry/insets.h"
#include "ui/gfx/geometry/vector2d.h"
#include "ui/gfx/paint_vector_icon.h"
#include "ui/strings/grit/ui_strings.h"
#include "ui/views/accessibility/view_accessibility.h"
#include "ui/views/animation/ink_drop.h"
#include "ui/views/bubble/bubble_dialog_delegate_view.h"
#include "ui/views/bubble/bubble_frame_view.h"
#include "ui/views/controls/button/button.h"
#include "ui/views/controls/button/checkbox.h"
#include "ui/views/controls/button/image_button.h"
#include "ui/views/controls/button/image_button_factory.h"
#include "ui/views/controls/button/label_button.h"
#include "ui/views/controls/highlight_path_generator.h"
#include "ui/views/controls/image_view.h"
#include "ui/views/controls/label.h"
#include "ui/views/controls/styled_label.h"
#include "ui/views/event_monitor.h"
#include "ui/views/layout/box_layout.h"
#include "ui/views/layout/box_layout_view.h"
#include "ui/views/layout/flex_layout.h"
#include "ui/views/layout/flex_layout_types.h"
#include "ui/views/layout/layout_provider.h"
#include "ui/views/layout/layout_types.h"
#include "ui/views/style/typography.h"
#include "ui/views/vector_icons.h"
#include "ui/views/view_class_properties.h"
#include "ui/views/widget/widget.h"

// The CaptionBubbleLabel needs to be focusable in order for NVDA to enable
// document navigation. It is suspected that other screen readers on Windows and
// Linux will need this behavior, too. VoiceOver and ChromeVox do not need the
// label to be focusable.
#if BUILDFLAG_INTERNAL_HAS_NATIVE_ACCESSIBILITY() && !BUILDFLAG(IS_MAC)
#define NEED_FOCUS_FOR_ACCESSIBILITY
#endif

#if defined(NEED_FOCUS_FOR_ACCESSIBILITY)
#include "base/scoped_observation.h"
#include "ui/accessibility/platform/ax_platform.h"
#endif

namespace {

// Formatting constants
static constexpr int kLineHeightDip =;
static constexpr int kLiveTranslateLabelLineHeightDip =;
static constexpr int kLiveTranslateImageWidthDip =;
static constexpr int kLanguageButtonImageLabelSpacing =;
static constexpr int kNumLinesCollapsed =;
static constexpr int kNumLinesExpanded =;
static constexpr int kCornerRadiusDip =;
static constexpr int kSidePaddingDip =;
static constexpr int kButtonDip =;
static constexpr int kButtonCircleHighlightPaddingDip =;
static constexpr int kMaxWidthDip =;
// Margin of the bubble with respect to the context window.
static constexpr int kMinAnchorMarginDip =;
static constexpr char kPrimaryFont[] =;
static constexpr char kSecondaryFont[] =;
static constexpr char kTertiaryFont[] =;
static constexpr int kFontSizePx =;
static constexpr int kLiveTranslateLabelFontSizePx =;
static constexpr double kDefaultRatioInParentX =;
static constexpr double kDefaultRatioInParentY =;
static constexpr int kErrorImageSizeDip =;
static constexpr int kErrorMessageBetweenChildSpacingDip =;
static constexpr int kNoActivityIntervalSeconds =;

constexpr base::TimeDelta kAnimationDuration =;

std::unique_ptr<views::ImageButton> BuildImageButton(
    views::Button::PressedCallback callback,
    const int tooltip_text_id) {}

// ui::CaptionStyle styles are CSS strings that can sometimes have !important.
// This method removes " !important" if it exists at the end of a CSS string.
std::string MaybeRemoveCSSImportant(std::string css_string) {}

// Parses a CSS color string that is in the form rgba and has a non-zero alpha
// value into an SkColor and sets it to be the value of the passed-in SkColor
// address. Returns whether or not the operation was a success.
//
// `css_string` is the CSS color string passed in. It is in the form
//     rgba(#,#,#,#). r, g, and b are integers between 0 and 255, inclusive.
//     a is a double between 0.0 and 1.0. There may be whitespace in between the
//     commas.
// `sk_color` is the address of an SKColor. If the operation is a success, the
//     function will set sk_color's value to be the parsed SkColor. If the
//     operation is not a success, sk_color's value will not change.
//
// As of spring 2021, all OS's use rgba to define the caption style colors.
// However, the ui::CaptionStyle spec also allows for the use of any valid CSS
// color spec. This function will need to be revisited should ui::CaptionStyle
// colors use non-rgba to define their colors.
bool ParseNonTransparentRGBACSSColorString(
    std::string css_string,
    SkColor* sk_color,
    const ui::ColorProvider* color_provider) {}

// Helper class for observing mouse and key events from native window.
class CaptionBubbleEventObserver : public ui::EventObserver {};

}  // namespace

namespace captions {

#if BUILDFLAG(IS_CHROMEOS_ASH)
DEFINE_UI_CLASS_PROPERTY_KEY(bool, kIsCaptionBubbleKey, false)
#endif

#if BUILDFLAG(IS_WIN)
class MediaFoundationRendererErrorMessageView : public views::StyledLabel {
  METADATA_HEADER(MediaFoundationRendererErrorMessageView, views::StyledLabel)

 public:
  explicit MediaFoundationRendererErrorMessageView(
      CaptionBubble* caption_bubble)
      : caption_bubble_(caption_bubble) {}

  // views::View:
  bool HandleAccessibleAction(const ui::AXActionData& action_data) override {
    switch (action_data.action) {
      case ax::mojom::Action::kDoDefault:
        caption_bubble_->OnContentSettingsLinkClicked();
        return true;
      default:
        break;
    }
    return views::StyledLabel::HandleAccessibleAction(action_data);
  }

 private:
  const raw_ptr<CaptionBubble> caption_bubble_;  // Not owned.
};

BEGIN_METADATA(MediaFoundationRendererErrorMessageView)
END_METADATA

#endif

// CaptionBubble implementation of BubbleFrameView. This class takes care
// of making the caption draggable.
class CaptionBubbleFrameView : public views::BubbleFrameView {};

BEGIN_METADATA()

class CaptionBubbleLabelAXModeObserver;

// CaptionBubble implementation of Label. This class takes care of setting up
// the accessible virtual views of the label in order to support braille
// accessibility. The CaptionBubbleLabel is a readonly document with a paragraph
// inside. Inside the paragraph are staticText nodes, one for each visual line
// in the rendered text of the label. These staticText nodes are shown on a
// braille display so that a braille user can read the caption text line by
// line.
class CaptionBubbleLabel : public views::Label {};

BEGIN_METADATA()

class LanguageLabelButton : public views::LabelButton {};

BEGIN_METADATA()

#if defined(NEED_FOCUS_FOR_ACCESSIBILITY)
// A helper class to the CaptionBubbleLabel which observes AXMode changes and
// updates the CaptionBubbleLabel focus behavior in response.
// TODO(crbug.com/40756389): Implement a ui::AXModeObserver::OnAXModeRemoved
// method which observes the removal of AXModes. Without that, the caption
// bubble label will remain focusable once accessibility is enabled, even if
// accessibility is later disabled.
class CaptionBubbleLabelAXModeObserver : public ui::AXModeObserver {};
#endif

CaptionBubble::CaptionBubble(PrefService* profile_prefs,
                             const std::string& application_locale,
                             base::OnceClosure destroyed_callback)
    :{}

CaptionBubble::~CaptionBubble() {}

gfx::Rect CaptionBubble::GetBubbleBounds() {}

void CaptionBubble::Init() {}

void CaptionBubble::OnBeforeBubbleWidgetInit(views::Widget::InitParams* params,
                                             views::Widget* widget) const {}

bool CaptionBubble::ShouldShowCloseButton() const {}

std::unique_ptr<views::NonClientFrameView>
CaptionBubble::CreateNonClientFrameView(views::Widget* widget) {}

void CaptionBubble::OnWidgetBoundsChanged(views::Widget* widget,
                                          const gfx::Rect& new_bounds) {}

void CaptionBubble::OnWidgetActivationChanged(views::Widget* widget,
                                              bool active) {}

void CaptionBubble::OnLiveTranslateEnabledChanged() {}

void CaptionBubble::OnLiveCaptionLanguageChanged() {}

void CaptionBubble::OnLiveTranslateTargetLanguageChanged() {}

void CaptionBubble::GetAccessibleNodeData(ui::AXNodeData* node_data) {}

std::u16string CaptionBubble::GetAccessibleWindowTitle() const {}

void CaptionBubble::OnThemeChanged() {}

void CaptionBubble::BackToTabButtonPressed() {}

void CaptionBubble::CloseButtonPressed() {}

void CaptionBubble::ExpandOrCollapseButtonPressed() {}

void CaptionBubble::PinOrUnpinButtonPressed() {}

void CaptionBubble::SwapButtons(views::Button* first_button,
                                views::Button* second_button,
                                bool show_first_button) {}

void CaptionBubble::CaptionSettingsButtonPressed() {}

void CaptionBubble::SetModel(CaptionBubbleModel* model) {}

void CaptionBubble::AnimationProgressed(const gfx::Animation* animation) {}

void CaptionBubble::OnTextChanged() {}

void CaptionBubble::OnDownloadProgressTextChanged() {}

void CaptionBubble::OnLanguagePackInstalled() {}

void CaptionBubble::OnAutoDetectedLanguageChanged() {}

bool CaptionBubble::ThemeColorsChanged() {}

void CaptionBubble::OnErrorChanged(
    CaptionBubbleErrorType error_type,
    OnErrorClickedCallback callback,
    OnDoNotShowAgainClickedCallback error_silenced_callback) {}

#if BUILDFLAG(IS_WIN)
void CaptionBubble::OnContentSettingsLinkClicked() {
  if (error_clicked_callback_) {
    error_clicked_callback_.Run();
  }
}
#endif

void CaptionBubble::UpdateControlsVisibility(bool show_controls) {}

void CaptionBubble::OnMouseEnteredOrExitedWindow(bool entered) {}

void CaptionBubble::UpdateBubbleAndTitleVisibility() {}

void CaptionBubble::UpdateBubbleVisibility() {}

void CaptionBubble::UpdateCaptionStyle(
    std::optional<ui::CaptionStyle> caption_style) {}

size_t CaptionBubble::GetTextIndexOfLineInLabel(size_t line) const {}

size_t CaptionBubble::GetNumLinesInLabel() const {}

int CaptionBubble::GetNumLinesVisible() {}

double CaptionBubble::GetTextScaleFactor() {}
const gfx::FontList CaptionBubble::GetFontList(int font_size) {}

void CaptionBubble::SetTextSizeAndFontFamily() {}

void CaptionBubble::SetTextColor() {}

void CaptionBubble::SetBackgroundColor() {}

void CaptionBubble::OnLanguageChanged() {}

void CaptionBubble::UpdateLanguageLabelText() {}

void CaptionBubble::RepositionInContextRect(CaptionBubbleModel::Id model_id,
                                            const gfx::Rect& context_rect) {}

void CaptionBubble::UpdateContentSize() {}

void CaptionBubble::Redraw() {}

void CaptionBubble::ShowInactive() {}

void CaptionBubble::Hide() {}

void CaptionBubble::OnInactivityTimeout() {}

void CaptionBubble::ResetInactivityTimer() {}

void CaptionBubble::MediaFoundationErrorCheckboxPressed() {}

bool CaptionBubble::HasMediaFoundationError() {}

void CaptionBubble::LogSessionEvent(SessionEvent event) {}

std::vector<raw_ptr<views::View, VectorExperimental>>
CaptionBubble::GetButtons() {}

bool CaptionBubble::HasActivity() {}

views::Label* CaptionBubble::GetLabelForTesting() {}

views::Label* CaptionBubble::GetDownloadProgressLabelForTesting() {}

views::Label* CaptionBubble::GetLanguageLabelForTesting() {}

bool CaptionBubble::IsGenericErrorMessageVisibleForTesting() const {}

void CaptionBubble::SetCaptionBubbleStyle() {}

base::RetainingOneShotTimer* CaptionBubble::GetInactivityTimerForTesting() {}

views::Button* CaptionBubble::GetCloseButtonForTesting() {}

views::Button* CaptionBubble::GetBackToTabButtonForTesting() {}

views::View* CaptionBubble::GetHeaderForTesting() {}

BEGIN_METADATA()

}  // namespace captions