Commit 83d7536f authored by Scott Violet's avatar Scott Violet Committed by Commit Bot

Moves PrintViewGraph into debug_utils

BUG=none
TEST=none

Change-Id: I35e8ccfba62d4037bbcbb4ab16bbc6185b42cf83
Reviewed-on: https://chromium-review.googlesource.com/1069319
Commit-Queue: Scott Violet <sky@chromium.org>
Reviewed-by: default avatarErik Chen <erikchen@chromium.org>
Cr-Commit-Position: refs/heads/master@{#560755}
parent a83f3108
...@@ -5,8 +5,8 @@ ...@@ -5,8 +5,8 @@
A simple debugging tool exists to help visualize the views tree during A simple debugging tool exists to help visualize the views tree during
debugging. It consists of 4 components: debugging. It consists of 4 components:
1. The function `View::PrintViewGraph()` (already in the file `view.cc` if 1. The function `views::PrintViewGraph()` (in the file
you've sync'd recently), `ui/views/debug_utils.h`),
1. a gdb script file `viewg.gdb` (see below), 1. a gdb script file `viewg.gdb` (see below),
1. the graphViz package (http://www.graphviz.org/ - downloadable for Linux, 1. the graphViz package (http://www.graphviz.org/ - downloadable for Linux,
Windows and Mac), and Windows and Mac), and
...@@ -17,7 +17,6 @@ debugging. It consists of 4 components: ...@@ -17,7 +17,6 @@ debugging. It consists of 4 components:
To use the tool, To use the tool,
1. Make sure you have 'dot' installed (part of graphViz), 1. Make sure you have 'dot' installed (part of graphViz),
1. define `TOUCH_DEBUG` and compile chrome with Views enabled,
1. run gdb on your build and 1. run gdb on your build and
1. `source viewg.gdb` (this can be done automatically in `.gdbinit`), 1. `source viewg.gdb` (this can be done automatically in `.gdbinit`),
1. stop at any breakpoint inside class `View` (or any derived class), and 1. stop at any breakpoint inside class `View` (or any derived class), and
...@@ -35,7 +34,7 @@ It is easy to modify the gdb script to generate PDF in case viewing with evince ...@@ -35,7 +34,7 @@ It is easy to modify the gdb script to generate PDF in case viewing with evince
If you don't use gdb, you may be able to adapt the script to work with your If you don't use gdb, you may be able to adapt the script to work with your
favorite debugger. The gdb script invokes favorite debugger. The gdb script invokes
this->PrintViewGraph(true) views::PrintViewGraph(this)
on the current object, returning `std::string`, whose contents must then be on the current object, returning `std::string`, whose contents must then be
saved to a file in order to be processed by dot. saved to a file in order to be processed by dot.
...@@ -54,7 +53,7 @@ define viewg ...@@ -54,7 +53,7 @@ define viewg
set logging overwrite on set logging overwrite on
set logging redirect on set logging redirect on
set logging on set logging on
printf "%s\n", this->PrintViewGraph(true).c_str() printf "%s\n", view::PrintViewGraph(this).c_str()
set logging off set logging off
shell dot -Tsvg -o ~/state.svg ~/state.dot shell dot -Tsvg -o ~/state.svg ~/state.dot
set pagination on set pagination on
......
...@@ -320,7 +320,7 @@ class COMPOSITOR_EXPORT Layer : public LayerAnimationDelegate, ...@@ -320,7 +320,7 @@ class COMPOSITOR_EXPORT Layer : public LayerAnimationDelegate,
// Returns the fallback SurfaceId set by SetFallbackSurfaceId. // Returns the fallback SurfaceId set by SetFallbackSurfaceId.
const viz::SurfaceId* GetFallbackSurfaceId() const; const viz::SurfaceId* GetFallbackSurfaceId() const;
bool has_external_content() { bool has_external_content() const {
return texture_layer_.get() || surface_layer_.get(); return texture_layer_.get() || surface_layer_.get();
} }
......
...@@ -9,6 +9,11 @@ ...@@ -9,6 +9,11 @@
#include "base/logging.h" #include "base/logging.h"
#include "ui/views/view.h" #include "ui/views/view.h"
#if !defined(NDEBUG)
#include "ui/gfx/geometry/angle_conversions.h"
#include "ui/gfx/transform_util.h"
#endif
namespace views { namespace views {
namespace { namespace {
void PrintViewHierarchyImp(const View* view, void PrintViewHierarchyImp(const View* view,
...@@ -53,6 +58,92 @@ void PrintFocusHierarchyImp(const View* view, ...@@ -53,6 +58,92 @@ void PrintFocusHierarchyImp(const View* view,
if (next_focusable) if (next_focusable)
PrintFocusHierarchyImp(next_focusable, indent, out); PrintFocusHierarchyImp(next_focusable, indent, out);
} }
#if !defined(NDEBUG)
std::string PrintViewGraphImpl(const View* view) {
// 64-bit pointer = 16 bytes of hex + "0x" + '\0' = 19.
const size_t kMaxPointerStringLength = 19;
std::string result;
// Node characteristics.
char p[kMaxPointerStringLength];
const std::string class_name(view->GetClassName());
size_t base_name_index = class_name.find_last_of('/');
if (base_name_index == std::string::npos)
base_name_index = 0;
else
base_name_index++;
constexpr size_t kBoundsBufferSize = 512;
char bounds_buffer[kBoundsBufferSize];
// Information about current node.
base::snprintf(p, kBoundsBufferSize, "%p", view);
result.append(" N");
result.append(p + 2);
result.append(" [label=\"");
result.append(class_name.substr(base_name_index).c_str());
base::snprintf(bounds_buffer, kBoundsBufferSize,
"\\n bounds: (%d, %d), (%dx%d)", view->bounds().x(),
view->bounds().y(), view->bounds().width(),
view->bounds().height());
result.append(bounds_buffer);
gfx::DecomposedTransform decomp;
if (!view->GetTransform().IsIdentity() &&
gfx::DecomposeTransform(&decomp, view->GetTransform())) {
base::snprintf(bounds_buffer, kBoundsBufferSize,
"\\n translation: (%f, %f)", decomp.translate[0],
decomp.translate[1]);
result.append(bounds_buffer);
base::snprintf(bounds_buffer, kBoundsBufferSize, "\\n rotation: %3.2f",
gfx::RadToDeg(std::acos(decomp.quaternion.w()) * 2));
result.append(bounds_buffer);
base::snprintf(bounds_buffer, kBoundsBufferSize,
"\\n scale: (%2.4f, %2.4f)", decomp.scale[0],
decomp.scale[1]);
result.append(bounds_buffer);
}
result.append("\"");
if (!view->parent())
result.append(", shape=box");
if (view->layer()) {
if (view->layer()->has_external_content())
result.append(", color=green");
else
result.append(", color=red");
if (view->layer()->fills_bounds_opaquely())
result.append(", style=filled");
}
result.append("]\n");
// Link to parent.
if (view->parent()) {
char pp[kMaxPointerStringLength];
base::snprintf(pp, kMaxPointerStringLength, "%p", view->parent());
result.append(" N");
result.append(pp + 2);
result.append(" -> N");
result.append(p + 2);
result.append("\n");
}
for (int i = 0; i < view->child_count(); ++i)
result.append(PrintViewGraphImpl(view->child_at(i)));
return result;
}
#endif
} // namespace } // namespace
void PrintViewHierarchy(const View* view) { void PrintViewHierarchy(const View* view) {
...@@ -71,4 +162,10 @@ void PrintFocusHierarchy(const View* view) { ...@@ -71,4 +162,10 @@ void PrintFocusHierarchy(const View* view) {
LOG(ERROR) << out.str(); LOG(ERROR) << out.str();
} }
#if !defined(NDEBUG)
std::string PrintViewGraph(const View* view) {
return "digraph {\n" + PrintViewGraphImpl(view) + "}\n";
}
#endif
} // namespace views } // namespace views
...@@ -5,6 +5,8 @@ ...@@ -5,6 +5,8 @@
#ifndef UI_VIEWS_DEBUG_UTILS_H_ #ifndef UI_VIEWS_DEBUG_UTILS_H_
#define UI_VIEWS_DEBUG_UTILS_H_ #define UI_VIEWS_DEBUG_UTILS_H_
#include <string>
#include "ui/views/views_export.h" #include "ui/views/views_export.h"
namespace views { namespace views {
...@@ -17,6 +19,13 @@ VIEWS_EXPORT void PrintViewHierarchy(const View* view); ...@@ -17,6 +19,13 @@ VIEWS_EXPORT void PrintViewHierarchy(const View* view);
// Log the focus traversal hierarchy. // Log the focus traversal hierarchy.
VIEWS_EXPORT void PrintFocusHierarchy(const View* view); VIEWS_EXPORT void PrintFocusHierarchy(const View* view);
#if !defined(NDEBUG)
// Returns string containing a graph of the views hierarchy in graphViz DOT
// language (http://graphviz.org/). Can be called within debugger and saved
// to a file to compile/view.
VIEWS_EXPORT std::string PrintViewGraph(const View* view);
#endif
} // namespace views } // namespace views
#endif // UI_VIEWS_DEBUG_UTILS_H_ #endif // UI_VIEWS_DEBUG_UTILS_H_
...@@ -1856,112 +1856,6 @@ PaintInfo::ScaleType View::GetPaintScaleType() const { ...@@ -1856,112 +1856,6 @@ PaintInfo::ScaleType View::GetPaintScaleType() const {
return PaintInfo::ScaleType::kScaleWithEdgeSnapping; return PaintInfo::ScaleType::kScaleWithEdgeSnapping;
} }
// Debugging -------------------------------------------------------------------
#if !defined(NDEBUG)
std::string View::PrintViewGraph(bool first) {
return DoPrintViewGraph(first, this);
}
std::string View::DoPrintViewGraph(bool first, View* view_with_children) {
// 64-bit pointer = 16 bytes of hex + "0x" + '\0' = 19.
const size_t kMaxPointerStringLength = 19;
std::string result;
if (first)
result.append("digraph {\n");
// Node characteristics.
char p[kMaxPointerStringLength];
const std::string class_name(GetClassName());
size_t base_name_index = class_name.find_last_of('/');
if (base_name_index == std::string::npos)
base_name_index = 0;
else
base_name_index++;
char bounds_buffer[512];
// Information about current node.
base::snprintf(p, arraysize(bounds_buffer), "%p", view_with_children);
result.append(" N");
result.append(p + 2);
result.append(" [label=\"");
result.append(class_name.substr(base_name_index).c_str());
base::snprintf(bounds_buffer,
arraysize(bounds_buffer),
"\\n bounds: (%d, %d), (%dx%d)",
bounds().x(),
bounds().y(),
bounds().width(),
bounds().height());
result.append(bounds_buffer);
gfx::DecomposedTransform decomp;
if (!GetTransform().IsIdentity() &&
gfx::DecomposeTransform(&decomp, GetTransform())) {
base::snprintf(bounds_buffer,
arraysize(bounds_buffer),
"\\n translation: (%f, %f)",
decomp.translate[0],
decomp.translate[1]);
result.append(bounds_buffer);
base::snprintf(bounds_buffer, arraysize(bounds_buffer),
"\\n rotation: %3.2f",
gfx::RadToDeg(std::acos(decomp.quaternion.w()) * 2));
result.append(bounds_buffer);
base::snprintf(bounds_buffer,
arraysize(bounds_buffer),
"\\n scale: (%2.4f, %2.4f)",
decomp.scale[0],
decomp.scale[1]);
result.append(bounds_buffer);
}
result.append("\"");
if (!parent_)
result.append(", shape=box");
if (layer()) {
if (layer()->has_external_content())
result.append(", color=green");
else
result.append(", color=red");
if (layer()->fills_bounds_opaquely())
result.append(", style=filled");
}
result.append("]\n");
// Link to parent.
if (parent_) {
char pp[kMaxPointerStringLength];
base::snprintf(pp, kMaxPointerStringLength, "%p", parent_);
result.append(" N");
result.append(pp + 2);
result.append(" -> N");
result.append(p + 2);
result.append("\n");
}
// Children.
for (auto* child : view_with_children->children_)
result.append(child->PrintViewGraph(false));
if (first)
result.append("}\n");
return result;
}
#endif
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// View, private: // View, private:
......
...@@ -1396,22 +1396,6 @@ class VIEWS_EXPORT View : public ui::LayerDelegate, ...@@ -1396,22 +1396,6 @@ class VIEWS_EXPORT View : public ui::LayerDelegate,
// hierarchy). // hierarchy).
virtual void OnNativeThemeChanged(const ui::NativeTheme* theme) {} virtual void OnNativeThemeChanged(const ui::NativeTheme* theme) {}
// Debugging -----------------------------------------------------------------
#if !defined(NDEBUG)
// Returns string containing a graph of the views hierarchy in graphViz DOT
// language (http://graphviz.org/). Can be called within debugger and save
// to a file to compile/view.
// Note: Assumes initial call made with first = true.
virtual std::string PrintViewGraph(bool first);
// Some classes may own an object which contains the children to displayed in
// the views hierarchy. The above function gives the class the flexibility to
// decide which object should be used to obtain the children, but this
// function makes the decision explicit.
std::string DoPrintViewGraph(bool first, View* view_with_children);
#endif
private: private:
friend class internal::PreEventDispatchHandler; friend class internal::PreEventDispatchHandler;
friend class internal::PostEventDispatchHandler; friend class internal::PostEventDispatchHandler;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment