// Copyright 2021 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 "ui/views/view_utils.h" #include #include "base/command_line.h" #include "base/debug/stack_trace.h" #include "base/logging.h" #include "ui/views/views_switches.h" DEFINE_EXPORTED_UI_CLASS_PROPERTY_TYPE(VIEWS_EXPORT, base::debug::StackTrace*) namespace views { DEFINE_OWNED_UI_CLASS_PROPERTY_KEY(base::debug::StackTrace, kViewStackTraceKey, nullptr) namespace { std::string GetViewTreeAsString(View* view) { if (!view->parent()) return view->GetClassName(); return GetViewTreeAsString(view->parent()) + " -> " + view->GetClassName(); } } // namespace ViewDebugWrapperImpl::ViewDebugWrapperImpl(View* view) : view_(view) {} ViewDebugWrapperImpl::~ViewDebugWrapperImpl() = default; std::string ViewDebugWrapperImpl::GetViewClassName() { return view_->GetClassName(); } int ViewDebugWrapperImpl::GetID() { return view_->GetID(); } debug::ViewDebugWrapper::BoundsTuple ViewDebugWrapperImpl::GetBounds() { const auto& bounds = view_->bounds(); return BoundsTuple(bounds.x(), bounds.y(), bounds.width(), bounds.height()); } bool ViewDebugWrapperImpl::GetVisible() { return view_->GetVisible(); } bool ViewDebugWrapperImpl::GetNeedsLayout() { return view_->needs_layout(); } bool ViewDebugWrapperImpl::GetEnabled() { return view_->GetEnabled(); } std::vector ViewDebugWrapperImpl::GetChildren() { children_.clear(); for (auto* child : view_->children()) children_.push_back(std::make_unique(child)); std::vector child_ptrs; for (auto& child : children_) child_ptrs.push_back(child.get()); return child_ptrs; } void ViewDebugWrapperImpl::ForAllProperties(PropCallback callback) { views::View* view = const_cast(view_.get()); for (auto* member : *(view->GetClassMetaData())) { auto flags = member->GetPropertyFlags(); if (!!(flags & ui::metadata::PropertyFlags::kSerializable)) { callback.Run(member->member_name(), base::UTF16ToUTF8(member->GetValueAsString(view))); } } } void PrintViewHierarchy(View* view, bool verbose, int depth) { ViewDebugWrapperImpl debug_view(view); std::ostringstream out; debug::PrintViewHierarchy(&out, &debug_view, verbose, depth); LOG(ERROR) << '\n' << out.str(); } std::string GetViewDebugInfo(View* view) { std::string debug_string = std::string("View: ") + view->GetClassName() + "\n"; debug_string += std::string("Hierarchy:\n ") + GetViewTreeAsString(view); debug_string += "\nView created here:\n"; static bool has_stack_trace = base::CommandLine::ForCurrentProcess()->HasSwitch( switches::kViewStackTraces); if (has_stack_trace) { debug_string += view->GetProperty(kViewStackTraceKey)->ToString(); } else { debug_string += std::string(" Run with --") + switches::kViewStackTraces + " to get a stack trace for when this View was created."; } return "\n" + debug_string; } } // namespace views