blob: 0ae52d34c6cee58130fda6e4ec87a6867d87b253 [file]
// Copyright 2026 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/ui/webui/devtools/greendev_floaty_ui.h"
#include "base/functional/bind.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "chrome/common/url_constants.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/web_ui.h"
#include "content/public/browser/web_ui_message_handler.h"
namespace {
class FloatyMessageHandler : public content::WebUIMessageHandler {
public:
FloatyMessageHandler() = default;
FloatyMessageHandler(const FloatyMessageHandler&) = delete;
FloatyMessageHandler& operator=(const FloatyMessageHandler&) = delete;
~FloatyMessageHandler() override = default;
private:
void HandleGetNodeDescription(const base::ListValue& args) {
AllowJavascript();
const base::Value& callback_id = args[0];
int process_id, routing_id, x, y;
base::StringToInt(args[1].GetString(), &process_id);
base::StringToInt(args[2].GetString(), &routing_id);
base::StringToInt(args[3].GetString(), &x);
base::StringToInt(args[4].GetString(), &y);
content::RenderFrameHost* rfh =
content::RenderFrameHost::FromID(process_id, routing_id);
if (!rfh || !rfh->IsRenderFrameLive()) {
ResolveJavascriptCallback(callback_id, base::Value(""));
return;
}
const std::string script = base::StringPrintf(
R"((function() {
const element = document.elementFromPoint(%d, %d);
if (!element) {
return '';
}
let description = element.tagName.toLowerCase();
if (element.id) {
description += '#' + element.id;
}
if (element.className) {
description += '.' + element.className.trim().replace(/\s+/g, '.');
}
return description;
})())",
x, y);
rfh->ExecuteJavaScript(
base::UTF8ToUTF16(script),
base::BindOnce(&FloatyMessageHandler::OnGotNodeDescription,
weak_ptr_factory_.GetWeakPtr(), callback_id.Clone()));
}
void OnGotNodeDescription(const base::Value& callback_id,
base::Value result) {
ResolveJavascriptCallback(callback_id, result);
}
void RegisterMessages() override {
web_ui()->RegisterMessageCallback(
"getNodeDescription",
base::BindRepeating(&FloatyMessageHandler::HandleGetNodeDescription,
base::Unretained(this)));
}
base::WeakPtrFactory<FloatyMessageHandler> weak_ptr_factory_{this};
};
} // namespace
GreenDevFloatyUI::GreenDevFloatyUI(content::WebUI* web_ui)
: content::WebUIController(web_ui) {
web_ui->AddMessageHandler(std::make_unique<FloatyMessageHandler>());
}
GreenDevFloatyUI::~GreenDevFloatyUI() = default;