blob: a217685244e4e817fd8ec70131b0787bf27eca79 [file] [log] [blame]
// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_BROWSER_UI_VIEWS_OMNIBOX_OMNIBOX_TEXT_VIEW_H_
#define CHROME_BROWSER_UI_VIEWS_OMNIBOX_OMNIBOX_TEXT_VIEW_H_
#include <stddef.h>
#include <memory>
#include <string_view>
#include "base/memory/raw_ptr.h"
#include "chrome/browser/ui/views/omnibox/omnibox_result_view.h"
#include "components/omnibox/browser/autocomplete_match.h"
#include "components/omnibox/browser/suggestion_answer.h"
#include "third_party/omnibox_proto/answer_data.pb.h"
#include "third_party/omnibox_proto/answer_type.pb.h"
#include "third_party/omnibox_proto/rich_answer_template.pb.h"
#include "ui/base/metadata/metadata_header_macros.h"
#include "ui/gfx/font_list.h"
#include "ui/views/view.h"
namespace gfx {
class Canvas;
class RenderText;
} // namespace gfx
// A view containing a render text styled via search results. This differs from
// the general purpose views::Label class by having less general features (such
// as selection) and more specific features (such as suggestion answer styling).
class OmniboxTextView : public views::View {
METADATA_HEADER(OmniboxTextView, views::View)
public:
explicit OmniboxTextView(OmniboxResultView* result_view);
OmniboxTextView(const OmniboxTextView&) = delete;
OmniboxTextView& operator=(const OmniboxTextView&) = delete;
~OmniboxTextView() override;
// views::View:
gfx::Size CalculatePreferredSize(
const views::SizeBounds& available_size) const override;
void OnPaint(gfx::Canvas* canvas) override;
// Applies given theme color to underlying render text. This is called Apply*
// instead of Set* because the only state kept is in render_text, so call this
// after setting text with methods below.
void ApplyTextColor(ui::ColorId id);
// Returns the render text, or an empty string if there is none.
std::u16string_view GetText() const;
// Used for content/description separator & tail suggest ellipses.
void SetText(std::u16string_view new_text);
// Used for standard suggestions.
void SetTextWithStyling(std::u16string_view new_text,
const ACMatchClassifications& classifications);
// Used for search answers using `RichAnswerTemplate`.
// Sets the styling for `FormattedString`'s `FormattedStringFragment`s.
// `fragment_index` specifies where to start appending and styling text from.
// Headlines should be styled differently than subheads.
void AppendAndStyleAnswerText(
const omnibox::FormattedString& formatted_string,
size_t fragment_index,
const omnibox::AnswerType& answer_type,
bool is_headline);
// Used for suggestions using `RichAnswerTemplate`.
void SetMultilineAnswerText(const omnibox::FormattedString& formatted_string,
const omnibox::AnswerType& answer_type);
// Used for history embedding answers.
void SetMultilineText(const std::u16string& text);
// Get the height of one line of text. This is handy if the view might have
// multiple lines.
int GetLineHeight() const;
// Reapplies text styling to the results text, based on the types of the match
// parts.
void ReapplyStyling();
// Creates a platform-approriate RenderText, sets its format to that of
// a suggestion and inserts (renders) the provided |text|.
std::unique_ptr<gfx::RenderText> CreateRenderText(
std::u16string_view text) const;
private:
// Updates the cached maximum line height and recomputes the preferred size.
void OnStyleChanged();
// To get color values.
raw_ptr<OmniboxResultView> result_view_;
// Font settings for this view.
int font_height_ = 0;
// Whether to wrap lines if the width is too narrow for the whole string.
// TODO(crbug.com/370088101): Ensure `wrap_text_lines_` is set correctly in
// the `SetTextWithStyling()` and related methods above. Can we use
// `render_text_->multiline()` instead? Ideally, all the text setting
// methods should detect if nothing has changed (i.e. text, style, and other
// options like wrapping / multiline, etc are all unchanged). If nothing has
// changed, then they should early exit because those methods are called
// 1000's of times per keystroke and cause noticeable lag when not
// early-exiting. Otherwise, if something has changed, the methods should
// explicitly set all these states and not assume they still hold their
// default values from initialization since `OmniboxTextView`s are reused.
bool wrap_text_lines_ = false;
// The primary data for this class.
std::unique_ptr<gfx::RenderText> render_text_;
// The classifications most recently passed to SetText. Used to exit
// early instead of setting text when the text and classifications
// match the current state of the view.
std::unique_ptr<ACMatchClassifications> cached_classifications_;
// Caches the param and return value of `CalculatePreferredSize()` for
// multiline texts. `CalculatePreferredSize()` is called 100's of times per
// keystroke. For 1-line texts, it's cached via `View::SetPreferredSize()`.
// But the size of multiline texts depends on `available_size`. Caching for
// the most recent `available_size` reduces the need to recompute preferred
// size from 300 to 4 times per keystroke. Increasing the cache size to 2
// would reduce it further to 0 times per keystroke, but that seems
// unnecessary. Unused for 1-line texts.
// The most recent `available_size` param passed to
// `CalculatePreferredSize()`.
mutable views::SizeBounds cached_available_size_;
// The most recent return value from `CalculatePreferredSize()`.
mutable gfx::Size cached_calculate_preferred_size_;
};
#endif // CHROME_BROWSER_UI_VIEWS_OMNIBOX_OMNIBOX_TEXT_VIEW_H_