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 |