srctree

Robin Linden parent 37db846f 8738faa0
browser/gui: Pass around a LayoutBox-ptr when dealing with hover stuff

This is less code, doesn't allocate, and gives us more information aboutwhat we hovered.

inlinesplit
browser/gui/app.cpp added: 23, removed: 36, total 0
@@ -59,31 +59,32 @@ void ensure_has_scheme(std::string &url) {
}
}
 
std::optional<std::string_view> try_get_uri(std::vector<dom::Node const *> const &);
std::string element_text(std::vector<dom::Node const *> const &dom_nodes) {
if (dom_nodes.empty()) {
std::optional<std::string_view> try_get_uri(layout::LayoutBox const *);
std::string element_text(layout::LayoutBox const *element) {
if (element == nullptr || element->node == nullptr) {
return ""s;
}
 
// Special handling of <a> because I want to see what link I'm hovering.
if (auto uri = try_get_uri(dom_nodes); uri.has_value()) {
if (auto uri = try_get_uri(element); uri.has_value()) {
return "a: "s + std::string{*uri};
}
 
if (auto const *text = std::get_if<dom::Text>(dom_nodes[0])) {
auto const &dom_node = element->node->node;
if (auto const *text = std::get_if<dom::Text>(&dom_node)) {
return text->text;
}
 
return std::get<dom::Element>(*dom_nodes[0]).name;
return std::get<dom::Element>(dom_node).name;
}
 
std::optional<std::string_view> try_get_uri(std::vector<dom::Node const *> const &nodes) {
if (nodes.empty()) {
std::optional<std::string_view> try_get_uri(layout::LayoutBox const *from) {
if (from == nullptr) {
return std::nullopt;
}
 
for (auto const *node : nodes) {
auto const *element = std::get_if<dom::Element>(node);
for (auto const *node = from->node; node != nullptr; node = node->parent) {
auto const *element = std::get_if<dom::Element>(&node->node);
if (element && element->name == "a"sv && element->attributes.contains("href")) {
return element->attributes.at("href");
}
@@ -100,15 +101,6 @@ std::string stylesheet_to_string(std::vector<css::Rule> const &stylesheet) {
return std::move(ss).str();
}
 
// Returns a vector containing [child, child->parent, child->parent->parent, ...].
std::vector<dom::Node const *> gather_node_and_parents(style::StyledNode const &child) {
std::vector<dom::Node const *> nodes;
for (style::StyledNode const *node = &child; node != nullptr; node = node->parent) {
nodes.push_back(&node->node);
}
return nodes;
}
 
namespace im {
// TODO(robinlinden): Stronger types.
// NOLINTNEXTLINE(bugprone-easily-swappable-parameters)
@@ -266,9 +258,9 @@ int App::run() {
 
auto window_position = geom::Position{event.mouseMove.x, event.mouseMove.y};
auto document_position = to_document_position(std::move(window_position));
auto const dom_nodes = get_hovered_nodes(document_position);
auto const *hovered = get_hovered_node(document_position);
nav_widget_extra_info_ =
fmt::format("{},{}: {}", document_position.x, document_position.y, element_text(dom_nodes));
fmt::format("{},{}: {}", document_position.x, document_position.y, element_text(hovered));
 
// If imgui is dealing with the mouse, we do nothing and let imgui change the cursor.
if (ImGui::GetIO().WantCaptureMouse) {
@@ -279,7 +271,7 @@ int App::run() {
// Otherwise we tell imgui not to mess with the cursor, and change it according to what we're
// currently hovering over.
ImGui::GetIO().ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange;
if (try_get_uri(dom_nodes).has_value()) {
if (try_get_uri(hovered).has_value()) {
cursor_.loadFromSystem(sf::Cursor::Hand);
} else {
cursor_.loadFromSystem(sf::Cursor::Arrow);
@@ -295,8 +287,8 @@ int App::run() {
 
auto window_position = geom::Position{event.mouseButton.x, event.mouseButton.y};
auto document_position = to_document_position(std::move(window_position));
auto const dom_nodes = get_hovered_nodes(std::move(document_position));
if (auto uri = try_get_uri(dom_nodes); uri.has_value()) {
auto const *hovered = get_hovered_node(std::move(document_position));
if (auto uri = try_get_uri(hovered); uri.has_value()) {
url_buf_ = std::string{*uri};
navigate();
}
@@ -408,18 +400,13 @@ void App::on_layout_updated() {
layout_str_ = layout != nullptr ? layout::to_string(*layout) : "";
}
 
std::vector<dom::Node const *> App::get_hovered_nodes(geom::Position document_position) const {
layout::LayoutBox const *App::get_hovered_node(geom::Position document_position) const {
auto const *layout = engine_.layout();
if (!page_loaded_ || layout == nullptr) {
return {};
return nullptr;
}
 
auto const *moused_over = layout::box_at_position(*layout, document_position);
if (moused_over == nullptr || moused_over->node == nullptr) {
return {};
}
 
return gather_node_and_parents(*moused_over->node);
return layout::box_at_position(*layout, document_position);
}
 
geom::Position App::to_document_position(geom::Position window_position) const {
 
browser/gui/app.h added: 23, removed: 36, total 0
@@ -9,7 +9,7 @@
#include "engine/engine.h"
#include "gfx/icanvas.h"
#include "gfx/sfml_canvas.h"
#include "layout/layout.h"
#include "layout/layout_box.h"
#include "protocol/handler_factory.h"
#include "uri/uri.h"
#include "util/history.h"
@@ -79,7 +79,7 @@ private:
void navigate();
void layout();
 
std::vector<dom::Node const *> get_hovered_nodes(geom::Position document_position) const;
layout::LayoutBox const *get_hovered_node(geom::Position document_position) const;
geom::Position to_document_position(geom::Position window_position) const;
 
void reset_scroll();