Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "ash/common/devtools/ash_devtools_css_agent.h" | 5 #include "ash/common/devtools/ash_devtools_css_agent.h" |
| 6 | 6 |
| 7 #include "ash/common/wm_lookup.h" | 7 #include "ash/common/wm_lookup.h" |
| 8 #include "ash/common/wm_window.h" | 8 #include "ash/common/wm_window.h" |
| 9 #include "base/strings/string_split.h" | 9 #include "base/strings/string_split.h" |
| 10 #include "base/strings/string_util.h" | 10 #include "base/strings/string_util.h" |
| 11 | 11 |
| 12 namespace ash { | 12 namespace ash { |
| 13 namespace devtools { | 13 namespace devtools { |
| 14 | 14 |
| 15 namespace { | 15 namespace { |
| 16 using namespace ui::devtools::protocol; | 16 using namespace ui::devtools::protocol; |
| 17 | 17 |
| 18 const char kHeight[] = "height"; | 18 const char kHeight[] = "height"; |
| 19 const char kWidth[] = "width"; | 19 const char kWidth[] = "width"; |
| 20 const char kX[] = "x"; | 20 const char kX[] = "x"; |
| 21 const char kY[] = "y"; | 21 const char kY[] = "y"; |
| 22 const char kVisibility[] = "visibility"; | |
| 22 | 23 |
| 23 std::unique_ptr<CSS::SourceRange> BuildDefaultSourceRange() { | 24 std::unique_ptr<CSS::SourceRange> BuildDefaultSourceRange() { |
| 24 // These tell the frontend where in the stylesheet a certain style | 25 // These tell the frontend where in the stylesheet a certain style |
| 25 // is located. Since we don't have stylesheets, this is all 0. | 26 // is located. Since we don't have stylesheets, this is all 0. |
| 26 // We need this because CSS fields are not editable unless | 27 // We need this because CSS fields are not editable unless |
| 27 // the range is provided. | 28 // the range is provided. |
| 28 return CSS::SourceRange::create() | 29 return CSS::SourceRange::create() |
| 29 .setStartLine(0) | 30 .setStartLine(0) |
| 30 .setEndLine(0) | 31 .setEndLine(0) |
| 31 .setStartColumn(0) | 32 .setStartColumn(0) |
| 32 .setEndColumn(0) | 33 .setEndColumn(0) |
| 33 .build(); | 34 .build(); |
| 34 } | 35 } |
| 35 | 36 |
| 36 std::unique_ptr<CSS::CSSProperty> BuildCSSProperty(const std::string& name, | 37 std::unique_ptr<CSS::CSSProperty> BuildCSSProperty(const std::string& name, |
| 37 int value) { | 38 int value) { |
| 38 return CSS::CSSProperty::create() | 39 return CSS::CSSProperty::create() |
| 39 .setRange(BuildDefaultSourceRange()) | 40 .setRange(BuildDefaultSourceRange()) |
| 40 .setName(name) | 41 .setName(name) |
| 41 .setValue(base::IntToString(value)) | 42 .setValue(base::IntToString(value)) |
| 42 .build(); | 43 .build(); |
| 43 } | 44 } |
| 44 | 45 |
| 45 std::unique_ptr<Array<CSS::CSSProperty>> BuildBoundsCSSPropertyArray( | 46 std::unique_ptr<Array<CSS::CSSProperty>> BuildCSSPropertyArray( |
| 46 const gfx::Rect& bounds) { | 47 const gfx::Rect& bounds, |
| 48 const bool& visible) { | |
|
varkha
2017/03/08 15:23:59
Here and below. No need to pass simple types by re
thanhph
2017/03/09 16:30:58
Done.
| |
| 47 auto cssProperties = Array<CSS::CSSProperty>::create(); | 49 auto cssProperties = Array<CSS::CSSProperty>::create(); |
| 48 cssProperties->addItem(BuildCSSProperty(kHeight, bounds.height())); | 50 cssProperties->addItem(BuildCSSProperty(kHeight, bounds.height())); |
| 49 cssProperties->addItem(BuildCSSProperty(kWidth, bounds.width())); | 51 cssProperties->addItem(BuildCSSProperty(kWidth, bounds.width())); |
| 50 cssProperties->addItem(BuildCSSProperty(kX, bounds.x())); | 52 cssProperties->addItem(BuildCSSProperty(kX, bounds.x())); |
| 51 cssProperties->addItem(BuildCSSProperty(kY, bounds.y())); | 53 cssProperties->addItem(BuildCSSProperty(kY, bounds.y())); |
| 54 cssProperties->addItem(BuildCSSProperty(kVisibility, visible)); | |
| 52 return cssProperties; | 55 return cssProperties; |
| 53 } | 56 } |
| 54 | 57 |
| 55 std::unique_ptr<CSS::CSSStyle> BuildCSSStyle(int node_id, | 58 std::unique_ptr<CSS::CSSStyle> BuildCSSStyle(int node_id, |
| 56 const gfx::Rect& bounds) { | 59 const gfx::Rect& bounds, |
| 60 const bool& visible) { | |
| 57 return CSS::CSSStyle::create() | 61 return CSS::CSSStyle::create() |
| 58 .setRange(BuildDefaultSourceRange()) | 62 .setRange(BuildDefaultSourceRange()) |
| 59 .setStyleSheetId(base::IntToString(node_id)) | 63 .setStyleSheetId(base::IntToString(node_id)) |
| 60 .setCssProperties(BuildBoundsCSSPropertyArray(bounds)) | 64 .setCssProperties(BuildCSSPropertyArray(bounds, visible)) |
| 61 .setShorthandEntries(Array<std::string>::create()) | 65 .setShorthandEntries(Array<std::string>::create()) |
| 62 .build(); | 66 .build(); |
| 63 } | 67 } |
| 64 | 68 |
| 65 Response ParseBounds(const std::string& style_text, gfx::Rect& bounds) { | |
| 66 std::vector<std::string> tokens = base::SplitString( | |
| 67 style_text, ":;", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY); | |
| 68 for (size_t i = 0; i < tokens.size() - 1; i += 2) { | |
| 69 const std::string& property = tokens.at(i); | |
| 70 int value; | |
| 71 if (!base::StringToInt(tokens.at(i + 1), &value)) | |
| 72 return Response::Error("Unable to parse value for property=" + property); | |
| 73 | |
| 74 if (property == kHeight) | |
| 75 bounds.set_height(std::max(0, value)); | |
| 76 else if (property == kWidth) | |
| 77 bounds.set_width(std::max(0, value)); | |
| 78 else if (property == kX) | |
| 79 bounds.set_x(value); | |
| 80 else if (property == kY) | |
| 81 bounds.set_y(value); | |
| 82 else | |
| 83 return Response::Error("Unsupported property=" + property); | |
| 84 } | |
| 85 return Response::OK(); | |
| 86 } | |
| 87 | |
| 88 } // namespace | 69 } // namespace |
| 89 | 70 |
| 90 AshDevToolsCSSAgent::AshDevToolsCSSAgent(AshDevToolsDOMAgent* dom_agent) | 71 AshDevToolsCSSAgent::AshDevToolsCSSAgent(AshDevToolsDOMAgent* dom_agent) |
| 91 : dom_agent_(dom_agent) { | 72 : dom_agent_(dom_agent) { |
| 92 DCHECK(dom_agent_); | 73 DCHECK(dom_agent_); |
| 93 } | 74 } |
| 94 | 75 |
| 95 AshDevToolsCSSAgent::~AshDevToolsCSSAgent() { | 76 AshDevToolsCSSAgent::~AshDevToolsCSSAgent() { |
| 96 disable(); | 77 disable(); |
| 97 } | 78 } |
| 98 | 79 |
| 99 ui::devtools::protocol::Response AshDevToolsCSSAgent::enable() { | 80 ui::devtools::protocol::Response AshDevToolsCSSAgent::enable() { |
| 100 dom_agent_->AddObserver(this); | 81 dom_agent_->AddObserver(this); |
| 101 return ui::devtools::protocol::Response::OK(); | 82 return ui::devtools::protocol::Response::OK(); |
| 102 } | 83 } |
| 103 | 84 |
| 104 ui::devtools::protocol::Response AshDevToolsCSSAgent::disable() { | 85 ui::devtools::protocol::Response AshDevToolsCSSAgent::disable() { |
| 105 dom_agent_->RemoveObserver(this); | 86 dom_agent_->RemoveObserver(this); |
| 106 return ui::devtools::protocol::Response::OK(); | 87 return ui::devtools::protocol::Response::OK(); |
| 107 } | 88 } |
| 108 | 89 |
| 109 ui::devtools::protocol::Response AshDevToolsCSSAgent::getMatchedStylesForNode( | 90 ui::devtools::protocol::Response AshDevToolsCSSAgent::getMatchedStylesForNode( |
| 110 int node_id, | 91 int node_id, |
| 111 ui::devtools::protocol::Maybe<ui::devtools::protocol::CSS::CSSStyle>* | 92 ui::devtools::protocol::Maybe<ui::devtools::protocol::CSS::CSSStyle>* |
| 112 inline_style) { | 93 inline_style) { |
| 113 *inline_style = GetStylesForNode(node_id); | 94 *inline_style = GetStylesForNode(node_id); |
| 114 if (!inline_style) { | 95 if (!inline_style) { |
| 115 return ui::devtools::protocol::Response::Error( | 96 return ui::devtools::protocol::Response::Error( |
| 116 "Node with that id not found"); | 97 "No node id " + std::to_string(node_id) + " found"); |
|
varkha
2017/03/08 15:23:59
Maybe format as "Node with id=<node_id> not found"
sadrul
2017/03/08 15:38:59
+1 re utility method to generate the error message
thanhph
2017/03/09 16:30:58
Done, thanks! A helper function is added in anon n
| |
| 117 } | 98 } |
| 118 return ui::devtools::protocol::Response::OK(); | 99 return ui::devtools::protocol::Response::OK(); |
| 119 } | 100 } |
| 120 | 101 |
| 121 ui::devtools::protocol::Response AshDevToolsCSSAgent::setStyleTexts( | 102 ui::devtools::protocol::Response AshDevToolsCSSAgent::setStyleTexts( |
| 122 std::unique_ptr<ui::devtools::protocol::Array< | 103 std::unique_ptr<ui::devtools::protocol::Array< |
| 123 ui::devtools::protocol::CSS::StyleDeclarationEdit>> edits, | 104 ui::devtools::protocol::CSS::StyleDeclarationEdit>> edits, |
| 124 std::unique_ptr< | 105 std::unique_ptr< |
| 125 ui::devtools::protocol::Array<ui::devtools::protocol::CSS::CSSStyle>>* | 106 ui::devtools::protocol::Array<ui::devtools::protocol::CSS::CSSStyle>>* |
| 126 result) { | 107 result) { |
| 127 std::unique_ptr< | 108 std::unique_ptr< |
| 128 ui::devtools::protocol::Array<ui::devtools::protocol::CSS::CSSStyle>> | 109 ui::devtools::protocol::Array<ui::devtools::protocol::CSS::CSSStyle>> |
| 129 updated_styles = ui::devtools::protocol::Array< | 110 updated_styles = ui::devtools::protocol::Array< |
| 130 ui::devtools::protocol::CSS::CSSStyle>::create(); | 111 ui::devtools::protocol::CSS::CSSStyle>::create(); |
| 131 for (size_t i = 0; i < edits->length(); i++) { | 112 for (size_t i = 0; i < edits->length(); i++) { |
| 132 auto* edit = edits->get(i); | 113 auto* edit = edits->get(i); |
| 133 int node_id; | 114 int node_id; |
| 134 if (!base::StringToInt(edit->getStyleSheetId(), &node_id)) | 115 if (!base::StringToInt(edit->getStyleSheetId(), &node_id)) |
| 135 return ui::devtools::protocol::Response::Error("Invalid node id"); | 116 return ui::devtools::protocol::Response::Error("Invalid node id"); |
| 136 | 117 |
| 137 gfx::Rect updated_bounds; | 118 gfx::Rect updated_bounds; |
| 138 if (!GetBoundsForNodeId(node_id, &updated_bounds)) { | 119 bool visible; |
| 120 if (!GetNodeIdProperties(node_id, &updated_bounds, &visible)) { | |
| 139 return ui::devtools::protocol::Response::Error( | 121 return ui::devtools::protocol::Response::Error( |
| 140 "No node found with that id"); | 122 "No node id " + std::to_string(node_id) + " found"); |
| 141 } | 123 } |
| 142 | |
| 143 ui::devtools::protocol::Response response( | 124 ui::devtools::protocol::Response response( |
| 144 ParseBounds(edit->getText(), updated_bounds)); | 125 ParseProperties(edit->getText(), &updated_bounds, &visible)); |
| 145 if (!response.isSuccess()) | 126 if (!response.isSuccess()) |
| 146 return response; | 127 return response; |
| 147 | 128 |
| 148 updated_styles->addItem(BuildCSSStyle(node_id, updated_bounds)); | 129 updated_styles->addItem(BuildCSSStyle(node_id, updated_bounds, visible)); |
| 149 if (!UpdateBounds(node_id, updated_bounds)) { | 130 |
| 131 if (!UpdateObjectProperties(node_id, updated_bounds, visible)) { | |
| 150 return ui::devtools::protocol::Response::Error( | 132 return ui::devtools::protocol::Response::Error( |
| 151 "No node found with that id"); | 133 "No node id " + std::to_string(node_id) + " found"); |
| 152 } | 134 } |
| 153 } | 135 } |
| 154 | |
| 155 *result = std::move(updated_styles); | 136 *result = std::move(updated_styles); |
| 156 return ui::devtools::protocol::Response::OK(); | 137 return ui::devtools::protocol::Response::OK(); |
| 157 } | 138 } |
| 158 | 139 |
| 159 void AshDevToolsCSSAgent::OnWindowBoundsChanged(WmWindow* window) { | 140 void AshDevToolsCSSAgent::OnWindowBoundsChanged(WmWindow* window) { |
| 160 InvalidateStyleSheet(dom_agent_->GetNodeIdFromWindow(window)); | 141 InvalidateStyleSheet(dom_agent_->GetNodeIdFromWindow(window)); |
| 161 } | 142 } |
| 162 | 143 |
| 163 void AshDevToolsCSSAgent::OnWidgetBoundsChanged(views::Widget* widget) { | 144 void AshDevToolsCSSAgent::OnWidgetBoundsChanged(views::Widget* widget) { |
| 164 InvalidateStyleSheet(dom_agent_->GetNodeIdFromWidget(widget)); | 145 InvalidateStyleSheet(dom_agent_->GetNodeIdFromWidget(widget)); |
| 165 } | 146 } |
| 166 | 147 |
| 167 void AshDevToolsCSSAgent::OnViewBoundsChanged(views::View* view) { | 148 void AshDevToolsCSSAgent::OnViewBoundsChanged(views::View* view) { |
| 168 InvalidateStyleSheet(dom_agent_->GetNodeIdFromView(view)); | 149 InvalidateStyleSheet(dom_agent_->GetNodeIdFromView(view)); |
| 169 } | 150 } |
| 170 | 151 |
| 171 std::unique_ptr<ui::devtools::protocol::CSS::CSSStyle> | 152 std::unique_ptr<ui::devtools::protocol::CSS::CSSStyle> |
| 172 AshDevToolsCSSAgent::GetStylesForNode(int node_id) { | 153 AshDevToolsCSSAgent::GetStylesForNode(int node_id) { |
| 173 gfx::Rect bounds; | 154 gfx::Rect bounds; |
| 174 return GetBoundsForNodeId(node_id, &bounds) ? BuildCSSStyle(node_id, bounds) | 155 bool visible; |
| 175 : nullptr; | 156 return GetNodeIdProperties(node_id, &bounds, &visible) |
| 157 ? BuildCSSStyle(node_id, bounds, visible) | |
| 158 : nullptr; | |
| 176 } | 159 } |
| 177 | 160 |
| 178 void AshDevToolsCSSAgent::InvalidateStyleSheet(int node_id) { | 161 void AshDevToolsCSSAgent::InvalidateStyleSheet(int node_id) { |
| 179 // The stylesheetId for each node is equivalent to its node_id (as a string). | 162 // The stylesheetId for each node is equivalent to its node_id (as a string). |
| 180 frontend()->styleSheetChanged(base::IntToString(node_id)); | 163 frontend()->styleSheetChanged(base::IntToString(node_id)); |
| 181 } | 164 } |
| 182 | 165 |
| 183 bool AshDevToolsCSSAgent::GetBoundsForNodeId(int node_id, gfx::Rect* bounds) { | 166 bool AshDevToolsCSSAgent::GetNodeIdProperties(int node_id, |
| 167 gfx::Rect* bounds, | |
| 168 bool* visible) { | |
| 184 WmWindow* window = dom_agent_->GetWindowFromNodeId(node_id); | 169 WmWindow* window = dom_agent_->GetWindowFromNodeId(node_id); |
| 185 if (window) { | 170 if (window) { |
| 186 *bounds = window->GetBounds(); | 171 *bounds = window->GetBounds(); |
| 172 *visible = window->IsVisible(); | |
| 187 return true; | 173 return true; |
| 188 } | 174 } |
| 189 | |
| 190 views::Widget* widget = dom_agent_->GetWidgetFromNodeId(node_id); | 175 views::Widget* widget = dom_agent_->GetWidgetFromNodeId(node_id); |
| 191 if (widget) { | 176 if (widget) { |
| 192 *bounds = widget->GetRestoredBounds(); | 177 *bounds = widget->GetRestoredBounds(); |
| 178 *visible = widget->IsVisible(); | |
| 193 return true; | 179 return true; |
| 194 } | 180 } |
| 195 | |
| 196 views::View* view = dom_agent_->GetViewFromNodeId(node_id); | 181 views::View* view = dom_agent_->GetViewFromNodeId(node_id); |
| 197 if (view) { | 182 if (view) { |
| 198 *bounds = view->bounds(); | 183 *bounds = view->bounds(); |
| 184 *visible = view->visible(); | |
| 199 return true; | 185 return true; |
| 200 } | 186 } |
| 201 | |
| 202 return false; | 187 return false; |
| 203 } | 188 } |
| 204 | 189 |
| 205 bool AshDevToolsCSSAgent::UpdateBounds(int node_id, const gfx::Rect& bounds) { | 190 bool AshDevToolsCSSAgent::UpdateObjectProperties(int node_id, |
| 191 const gfx::Rect& bounds, | |
| 192 const bool& visible) { | |
| 206 WmWindow* window = dom_agent_->GetWindowFromNodeId(node_id); | 193 WmWindow* window = dom_agent_->GetWindowFromNodeId(node_id); |
| 207 if (window) { | 194 if (window) { |
| 208 window->SetBounds(bounds); | 195 window->SetBounds(bounds); |
| 196 if (visible != window->IsVisible()) { | |
| 197 if (visible) | |
| 198 window->Show(); | |
| 199 else | |
| 200 window->Hide(); | |
| 201 } | |
| 209 return true; | 202 return true; |
| 210 } | 203 } |
| 211 | |
| 212 views::Widget* widget = dom_agent_->GetWidgetFromNodeId(node_id); | 204 views::Widget* widget = dom_agent_->GetWidgetFromNodeId(node_id); |
| 213 if (widget) { | 205 if (widget) { |
| 214 widget->SetBounds(bounds); | 206 widget->SetBounds(bounds); |
| 207 if (visible != widget->IsVisible()) { | |
| 208 if (visible) | |
| 209 widget->Show(); | |
| 210 else | |
| 211 widget->Hide(); | |
| 212 } | |
| 215 return true; | 213 return true; |
| 216 } | 214 } |
| 217 | |
| 218 views::View* view = dom_agent_->GetViewFromNodeId(node_id); | 215 views::View* view = dom_agent_->GetViewFromNodeId(node_id); |
| 219 if (view) { | 216 if (view) { |
| 220 view->SetBoundsRect(bounds); | 217 view->SetBoundsRect(bounds); |
| 218 if (visible != view->visible()) | |
| 219 view->SetVisible(visible); | |
| 221 return true; | 220 return true; |
| 222 } | 221 } |
| 222 return false; | |
| 223 } | |
| 223 | 224 |
| 224 return false; | 225 Response AshDevToolsCSSAgent::ParseProperties(const std::string& style_text, |
| 226 gfx::Rect* bounds, | |
| 227 bool* visible) { | |
| 228 std::vector<std::string> tokens = base::SplitString( | |
| 229 style_text, ":;", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY); | |
| 230 for (size_t i = 0; i < tokens.size() - 1; i += 2) { | |
| 231 const std::string& property = tokens.at(i); | |
| 232 int value; | |
| 233 if (!base::StringToInt(tokens.at(i + 1), &value)) | |
| 234 return Response::Error("Unable to parse value for property=" + property); | |
| 235 | |
| 236 if (property == kHeight) | |
| 237 bounds->set_height(std::max(0, value)); | |
| 238 else if (property == kWidth) | |
| 239 bounds->set_width(std::max(0, value)); | |
| 240 else if (property == kX) | |
| 241 bounds->set_x(value); | |
| 242 else if (property == kY) | |
| 243 bounds->set_y(value); | |
| 244 else if (property == kVisibility) | |
| 245 *visible = std::max(0, value) == 1; | |
| 246 else | |
| 247 return Response::Error("Unsupported property=" + property); | |
| 248 } | |
| 249 return Response::OK(); | |
| 225 } | 250 } |
| 226 | 251 |
| 227 } // namespace devtools | 252 } // namespace devtools |
| 228 } // namespace ash | 253 } // namespace ash |
| OLD | NEW |