Skip to content

Commit

Permalink
Add sources to UI DevTools
Browse files Browse the repository at this point in the history
A link to a source is now displayed in the element properties panel.
Clicking on the link opens the source panel where the header file is
loaded. Right clicking on the link gives the option to open in new tab,
which opens the header file in Chromium code search.

Change-Id: I0314ff285e727bdcc7a9a58201cb6f9089a4c718
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1719164
Commit-Queue: Kristyn Hamasaki <khamasaki@google.com>
Reviewed-by: Wei Li <weili@chromium.org>
Cr-Commit-Position: refs/heads/master@{#686116}
  • Loading branch information
Kristyn Hamasaki authored and Commit Bot committed Aug 12, 2019
1 parent 0869f48 commit 4de3d0a
Show file tree
Hide file tree
Showing 24 changed files with 565 additions and 19 deletions.
5 changes: 5 additions & 0 deletions components/test/data/ui_devtools/test_file.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// This file is for testing GetSource.
6 changes: 6 additions & 0 deletions components/ui_devtools/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,8 @@ inspector_protocol_generate("protocol_generated_sources") {
component("ui_devtools") {
sources = rebase_path(_protocol_generated, ".", target_gen_dir)
sources += [
"agent_util.cc",
"agent_util.h",
"css_agent.cc",
"css_agent.h",
"devtools_base_agent.h",
Expand Down Expand Up @@ -142,6 +144,10 @@ source_set("unit_tests") {
"devtools_server_unittest.cc",
]

data = [
"//components/test/data/ui_devtools/test_file.cc",
]

deps = [
":test_support",
"//base/test:test_support",
Expand Down
55 changes: 55 additions & 0 deletions components/ui_devtools/agent_util.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "components/ui_devtools/agent_util.h"

#include "base/command_line.h"
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/path_service.h"
#include "base/run_loop.h"
#include "base/task/post_task.h"
#include "base/task/task_traits.h"

namespace ui_devtools {

namespace {

void OnSourceFile(base::OnceClosure quit_closure,
bool* return_value,
bool read_file_result) {
*return_value = read_file_result;
std::move(quit_closure).Run();
}

} // namespace

const char kChromiumCodeSearchURL[] = "https://cs.chromium.org/";
const char kChromiumCodeSearchSrcURL[] =
"https://cs.chromium.org/chromium/src/";

bool GetSourceCode(std::string path, std::string* source_code) {
base::FilePath src_dir;
base::PathService::Get(base::DIR_SOURCE_ROOT, &src_dir);
src_dir = src_dir.AppendASCII(path);

base::RunLoop run_loop(base::RunLoop::Type::kNestableTasksAllowed);

bool return_value;
base::PostTaskAndReplyWithResult(
FROM_HERE,
{base::MayBlock(), base::TaskPriority::USER_VISIBLE,
base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN},
base::BindOnce(&base::ReadFileToString, src_dir, source_code),
base::BindOnce(&OnSourceFile, run_loop.QuitClosure(), &return_value));

run_loop.Run();

if (!return_value)
DLOG(ERROR) << "Could not get source file of " << src_dir.value() << ".";

return return_value;
}

} // namespace ui_devtools
22 changes: 22 additions & 0 deletions components/ui_devtools/agent_util.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef COMPONENTS_UI_DEVTOOLS_AGENT_UTIL_H_
#define COMPONENTS_UI_DEVTOOLS_AGENT_UTIL_H_

#include "base/files/file_path.h"
#include "components/ui_devtools/devtools_export.h"

namespace ui_devtools {

UI_DEVTOOLS_EXPORT extern const char kChromiumCodeSearchURL[];
UI_DEVTOOLS_EXPORT extern const char kChromiumCodeSearchSrcURL[];

// Synchonously gets source code and returns true if successful.
bool UI_DEVTOOLS_EXPORT GetSourceCode(std::string path,
std::string* source_code);

} // namespace ui_devtools

#endif // COMPONENTS_UI_DEVTOOLS_AGENT_UTIL_H_
54 changes: 53 additions & 1 deletion components/ui_devtools/css_agent.cc
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

#include "base/strings/string_split.h"
#include "base/strings/string_util.h"
#include "components/ui_devtools/agent_util.h"
#include "components/ui_devtools/ui_element.h"

namespace ui_devtools {
Expand Down Expand Up @@ -90,6 +91,7 @@ std::unique_ptr<protocol::CSS::CSSRule> BuildCSSRule(
std::string stylesheet_uid,
const UIElement::ClassProperties& class_properties) {
return protocol::CSS::CSSRule::create()
.setStyleSheetId(stylesheet_uid)
.setSelectorList(BuildSelectorList(class_properties.class_name_))
.setStyle(BuildCSSStyle(stylesheet_uid, class_properties.properties_))
.build();
Expand Down Expand Up @@ -167,6 +169,21 @@ Response ParseProperties(const std::string& style_text,
return Response::OK();
}

std::unique_ptr<protocol::CSS::CSSStyleSheetHeader>
BuildObjectForStyleSheetInfo(std::string stylesheet_uid,
std::string url_path,
int line) {
std::unique_ptr<protocol::CSS::CSSStyleSheetHeader> result =
protocol::CSS::CSSStyleSheetHeader::create()
.setStyleSheetId(stylesheet_uid)
.setSourceURL(kChromiumCodeSearchSrcURL + url_path +
"?l=" + base::NumberToString(line))
.setStartLine(line)
.setStartColumn(0)
.build();
return result;
}

} // namespace

CSSAgent::CSSAgent(DOMAgent* dom_agent) : dom_agent_(dom_agent) {
Expand Down Expand Up @@ -198,6 +215,29 @@ Response CSSAgent::getMatchedStylesForNode(
return Response::OK();
}

Response CSSAgent::getStyleSheetText(const protocol::String& style_sheet_id,
protocol::String* result) {
int node_id;
int stylesheet_id;
std::vector<std::string> ids = base::SplitString(
style_sheet_id, "_", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
if (ids.size() < 2 || !base::StringToInt(ids[0], &node_id) ||
!base::StringToInt(ids[1], &stylesheet_id))
return Response::Error("Invalid stylesheet id");

UIElement* ui_element = dom_agent_->GetElementFromNodeId(node_id);
if (!ui_element)
return Response::Error("Node id not found");

auto sources = ui_element->GetSources();
if (static_cast<int>(sources.size()) <= stylesheet_id)
return Response::Error("Stylesheet id not found");

if (GetSourceCode(sources[stylesheet_id].path_, result))
return protocol::Response::OK();
return protocol::Response::Error("Could not read source file");
}

Response CSSAgent::setStyleTexts(
std::unique_ptr<Array<CSS::StyleDeclarationEdit>> edits,
std::unique_ptr<Array<CSS::CSSStyle>>* result) {
Expand Down Expand Up @@ -291,8 +331,20 @@ CSSAgent::BuildMatchedStyles(UIElement* ui_element) {
.setMatchingSelectors(BuildDefaultMatchingSelectors())
.build());
}

if (!ui_element->header_sent()) {
InitStylesheetHeaders(ui_element);
}
return result;
}

void CSSAgent::InitStylesheetHeaders(UIElement* ui_element) {
std::vector<UIElement::Source> sources = ui_element->GetSources();
for (size_t i = 0; i < sources.size(); i++) {
frontend()->styleSheetAdded(BuildObjectForStyleSheetInfo(
BuildStylesheetUId(ui_element->node_id(), i), sources[i].path_,
sources[i].line_));
}
ui_element->set_header_sent();
}

} // namespace ui_devtools
5 changes: 5 additions & 0 deletions components/ui_devtools/css_agent.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ class UI_DEVTOOLS_EXPORT CSSAgent
int node_id,
protocol::Maybe<protocol::Array<protocol::CSS::RuleMatch>>*
matched_css_rules) override;
protocol::Response getStyleSheetText(const protocol::String& style_sheet_id,
protocol::String* text) override;
protocol::Response setStyleTexts(
std::unique_ptr<protocol::Array<protocol::CSS::StyleDeclarationEdit>>
edits,
Expand All @@ -53,6 +55,9 @@ class UI_DEVTOOLS_EXPORT CSSAgent
std::unique_ptr<protocol::Array<protocol::CSS::RuleMatch>> BuildMatchedStyles(
UIElement* ui_element);

// Sends header to frontend for each section in properties panel.
void InitStylesheetHeaders(UIElement* ui_element);

DOMAgent* const dom_agent_;

DISALLOW_COPY_AND_ASSIGN(CSSAgent);
Expand Down
36 changes: 36 additions & 0 deletions components/ui_devtools/css_agent_unittest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@

#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
#include "base/test/scoped_task_environment.h"
#include "components/ui_devtools/agent_util.h"
#include "components/ui_devtools/dom_agent.h"
#include "components/ui_devtools/ui_devtools_unittest_utils.h"
#include "components/ui_devtools/ui_element.h"
Expand All @@ -30,6 +32,9 @@ class FakeUIElement : public UIElement {
}
bool visible() const { return visible_; }
gfx::Rect bounds() const { return bounds_; }
void AddSource(std::string path, int line) {
UIElement::AddSource(path, line);
}

private:
gfx::Rect bounds_;
Expand Down Expand Up @@ -84,6 +89,7 @@ class CSSAgentTest : public testing::Test {
}

protected:
base::test::ScopedTaskEnvironment scoped_task_environment_;
using StyleArray = protocol::Array<protocol::CSS::CSSStyle>;

std::pair<bool, std::unique_ptr<StyleArray>>
Expand Down Expand Up @@ -115,13 +121,21 @@ class CSSAgentTest : public testing::Test {
}
return std::string();
}

int GetStyleSheetChangedCount(std::string stylesheet_id) {
return frontend_channel_->CountProtocolNotificationMessage(
"{\"method\":\"CSS.styleSheetChanged\",\"params\":{"
"\"styleSheetId\":\"" +
stylesheet_id + "\"}}");
}

std::pair<bool, std::string> GetSourceForElement() {
std::string output;
auto response = css_agent_->getStyleSheetText(
BuildStylesheetUId(element()->node_id(), 0), &output);
return {response.isSuccess(), output};
}

CSSAgent* css_agent() { return css_agent_.get(); }
DOMAgent* dom_agent() { return dom_agent_.get(); }
FakeUIElement* element() { return element_.get(); }
Expand Down Expand Up @@ -302,4 +316,26 @@ TEST_F(CSSAgentTest, UpdateOnBoundsChange) {
EXPECT_EQ(2, GetStyleSheetChangedCount(another_element_stylesheet_id));
}

TEST_F(CSSAgentTest, GetSource) {
std::string file = "components/test/data/ui_devtools/test_file.cc";
element()->AddSource(file, 0);
auto result = GetSourceForElement();

EXPECT_TRUE(result.first);

std::string source_code;
DCHECK(GetSourceCode(file, &source_code));
DCHECK(source_code != "");

EXPECT_EQ(result.second, source_code);
}

TEST_F(CSSAgentTest, BadPathFails) {
element()->AddSource("not/a/real/path", 0);
auto result = GetSourceForElement();

EXPECT_FALSE(result.first);
EXPECT_EQ(result.second, "");
}

} // namespace ui_devtools

0 comments on commit 4de3d0a

Please sign in to comment.