Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2017 The Chromium Authors. All rights reserved. | 1 // Copyright 2017 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 "chrome/browser/android/vr_shell/textures/url_bar_texture.h" | 5 #include "chrome/browser/android/vr_shell/textures/url_bar_texture.h" |
| 6 | 6 |
| 7 #include "base/strings/utf_string_conversions.h" | 7 #include "base/strings/utf_string_conversions.h" |
| 8 #include "cc/paint/skia_paint_canvas.h" | 8 #include "cc/paint/skia_paint_canvas.h" |
| 9 #include "chrome/browser/android/vr_shell/color_scheme.h" | 9 #include "chrome/browser/android/vr_shell/color_scheme.h" |
| 10 #include "chrome/browser/android/vr_shell/textures/render_text_wrapper.h" | 10 #include "chrome/browser/android/vr_shell/textures/render_text_wrapper.h" |
| 11 #include "components/strings/grit/components_strings.h" | |
| 12 #include "components/toolbar/vector_icons.h" | |
| 13 #include "components/url_formatter/url_formatter.h" | 11 #include "components/url_formatter/url_formatter.h" |
| 14 #include "ui/base/l10n/l10n_util.h" | |
| 15 #include "ui/gfx/canvas.h" | 12 #include "ui/gfx/canvas.h" |
| 16 #include "ui/gfx/font.h" | 13 #include "ui/gfx/font.h" |
| 17 #include "ui/gfx/font_list.h" | 14 #include "ui/gfx/font_list.h" |
| 18 #include "ui/gfx/geometry/point_f.h" | 15 #include "ui/gfx/geometry/point_f.h" |
| 19 #include "ui/gfx/geometry/rect.h" | 16 #include "ui/gfx/geometry/rect.h" |
| 20 #include "ui/gfx/paint_vector_icon.h" | 17 #include "ui/gfx/paint_vector_icon.h" |
| 21 #include "ui/gfx/render_text.h" | 18 #include "ui/gfx/render_text.h" |
| 22 #include "ui/gfx/vector_icon_types.h" | |
| 23 #include "ui/vector_icons/vector_icons.h" | 19 #include "ui/vector_icons/vector_icons.h" |
| 24 | 20 |
| 25 namespace vr_shell { | 21 namespace vr_shell { |
| 26 | 22 |
| 27 namespace { | 23 namespace { |
| 28 | 24 |
| 29 static constexpr float kWidth = 0.672; | 25 static constexpr float kWidth = 0.672; |
| 30 static constexpr float kHeight = 0.088; | 26 static constexpr float kHeight = 0.088; |
| 31 static constexpr float kFontHeight = 0.027; | 27 static constexpr float kFontHeight = 0.027; |
| 32 static constexpr float kBackButtonWidth = kHeight; | 28 static constexpr float kBackButtonWidth = kHeight; |
| 33 static constexpr float kBackIconHeight = 0.0375; | 29 static constexpr float kBackIconHeight = 0.0375; |
| 34 static constexpr float kBackIconOffset = 0.005; | 30 static constexpr float kBackIconOffset = 0.005; |
| 35 static constexpr float kFieldSpacing = 0.014; | 31 static constexpr float kFieldSpacing = 0.014; |
| 36 static constexpr float kSecurityIconHeight = 0.03; | 32 static constexpr float kSecurityIconSize = 0.03; |
| 37 static constexpr float kUrlRightMargin = 0.02; | 33 static constexpr float kUrlRightMargin = 0.02; |
| 38 static constexpr float kSeparatorWidth = 0.002; | 34 static constexpr float kSeparatorWidth = 0.002; |
| 39 static constexpr float kChipTextLineMargin = kHeight * 0.3; | 35 static constexpr float kChipTextLineMargin = kHeight * 0.3; |
| 40 | 36 |
| 41 using security_state::SecurityLevel; | 37 using security_state::SecurityLevel; |
| 42 | 38 |
| 43 // See ToolbarModelImpl::GetVectorIcon(). | |
| 44 const struct gfx::VectorIcon& GetSecurityIcon(SecurityLevel level) { | |
| 45 switch (level) { | |
| 46 case security_state::NONE: | |
| 47 case security_state::HTTP_SHOW_WARNING: | |
| 48 return toolbar::kHttpIcon; | |
| 49 case security_state::EV_SECURE: | |
| 50 case security_state::SECURE: | |
| 51 return toolbar::kHttpsValidIcon; | |
| 52 case security_state::SECURITY_WARNING: | |
| 53 // Surface Dubious as Neutral. | |
| 54 return toolbar::kHttpIcon; | |
| 55 case security_state::SECURE_WITH_POLICY_INSTALLED_CERT: // ChromeOS only. | |
| 56 return ui::kBusinessIcon; | |
| 57 case security_state::DANGEROUS: | |
| 58 return toolbar::kHttpsInvalidIcon; | |
| 59 default: | |
| 60 NOTREACHED(); | |
| 61 return toolbar::kHttpsInvalidIcon; | |
| 62 } | |
| 63 } | |
| 64 | |
| 65 // See LocationBarView::GetSecureTextColor(). | 39 // See LocationBarView::GetSecureTextColor(). |
| 66 SkColor GetSchemeColor(SecurityLevel level, const ColorScheme& color_scheme) { | 40 SkColor GetSchemeColor(SecurityLevel level, const ColorScheme& color_scheme) { |
| 67 switch (level) { | 41 switch (level) { |
| 68 case SecurityLevel::NONE: | 42 case SecurityLevel::NONE: |
| 69 case SecurityLevel::HTTP_SHOW_WARNING: | 43 case SecurityLevel::HTTP_SHOW_WARNING: |
| 70 return color_scheme.url_deemphasized; | 44 return color_scheme.url_deemphasized; |
| 71 case SecurityLevel::EV_SECURE: | 45 case SecurityLevel::EV_SECURE: |
| 72 case SecurityLevel::SECURE: | 46 case SecurityLevel::SECURE: |
| 73 return color_scheme.secure; | 47 return color_scheme.secure; |
| 74 case SecurityLevel::SECURITY_WARNING: | 48 case SecurityLevel::SECURITY_WARNING: |
| 75 return color_scheme.url_deemphasized; | 49 return color_scheme.url_deemphasized; |
| 76 case SecurityLevel::SECURE_WITH_POLICY_INSTALLED_CERT: // ChromeOS only. | 50 case SecurityLevel::SECURE_WITH_POLICY_INSTALLED_CERT: // ChromeOS only. |
| 77 return color_scheme.insecure; | 51 return color_scheme.insecure; |
| 78 case SecurityLevel::DANGEROUS: | 52 case SecurityLevel::DANGEROUS: |
| 79 return color_scheme.insecure; | 53 return color_scheme.insecure; |
| 80 default: | 54 default: |
| 81 NOTREACHED(); | 55 NOTREACHED(); |
| 82 return color_scheme.insecure; | 56 return color_scheme.insecure; |
| 83 } | 57 } |
| 84 } | 58 } |
| 85 | 59 |
| 86 // See ToolbarModelImpl::GetSecureVerboseText(). | |
| 87 int GetSecurityTextId(SecurityLevel level, bool malware) { | |
| 88 switch (level) { | |
| 89 case security_state::HTTP_SHOW_WARNING: | |
| 90 return IDS_NOT_SECURE_VERBOSE_STATE; | |
| 91 case security_state::SECURE: | |
| 92 return IDS_SECURE_VERBOSE_STATE; | |
| 93 case security_state::DANGEROUS: | |
| 94 return (malware ? IDS_DANGEROUS_VERBOSE_STATE | |
| 95 : IDS_NOT_SECURE_VERBOSE_STATE); | |
| 96 default: | |
| 97 return 0; | |
| 98 } | |
| 99 } | |
| 100 | |
| 101 void setEmphasis(vr_shell::RenderTextWrapper* render_text, | 60 void setEmphasis(vr_shell::RenderTextWrapper* render_text, |
| 102 bool emphasis, | 61 bool emphasis, |
| 103 const gfx::Range& range, | 62 const gfx::Range& range, |
| 104 const ColorScheme& color_scheme) { | 63 const ColorScheme& color_scheme) { |
| 105 SkColor color = | 64 SkColor color = |
| 106 emphasis ? color_scheme.url_emphasized : color_scheme.url_deemphasized; | 65 emphasis ? color_scheme.url_emphasized : color_scheme.url_deemphasized; |
| 107 if (range.IsValid()) { | 66 if (range.IsValid()) { |
| 108 render_text->ApplyColor(color, range); | 67 render_text->ApplyColor(color, range); |
| 109 } else { | 68 } else { |
| 110 render_text->SetColor(color); | 69 render_text->SetColor(color); |
| 111 } | 70 } |
| 112 } | 71 } |
| 113 | 72 |
| 114 gfx::PointF percentToMeters(const gfx::PointF& percent) { | 73 gfx::PointF percentToMeters(const gfx::PointF& percent) { |
| 115 return gfx::PointF(percent.x() * kWidth, percent.y() * kHeight); | 74 return gfx::PointF(percent.x() * kWidth, percent.y() * kHeight); |
| 116 } | 75 } |
| 117 | 76 |
| 118 } // namespace | 77 } // namespace |
| 119 | 78 |
| 120 UrlBarTexture::UrlBarTexture( | 79 UrlBarTexture::UrlBarTexture( |
| 121 bool web_vr, | 80 bool web_vr, |
| 122 const base::Callback<void(UiUnsupportedMode)>& failure_callback) | 81 const base::Callback<void(UiUnsupportedMode)>& failure_callback) |
| 123 : security_level_(SecurityLevel::DANGEROUS), | 82 : has_back_button_(!web_vr), |
| 124 has_back_button_(!web_vr), | |
| 125 has_security_chip_(false), | 83 has_security_chip_(false), |
| 126 failure_callback_(failure_callback) {} | 84 failure_callback_(failure_callback) {} |
| 127 | 85 |
| 128 UrlBarTexture::~UrlBarTexture() = default; | 86 UrlBarTexture::~UrlBarTexture() = default; |
| 129 | 87 |
| 130 void UrlBarTexture::SetURL(const GURL& gurl) { | 88 void UrlBarTexture::SetToolbarState(const ToolbarState& state) { |
| 131 if (gurl_ != gurl) | 89 if (state_ == state) |
| 132 set_dirty(); | 90 return; |
| 133 gurl_ = gurl; | 91 state_ = state; |
| 92 set_dirty(); | |
| 134 } | 93 } |
| 135 | 94 |
| 136 void UrlBarTexture::SetHistoryButtonsEnabled(bool can_go_back) { | 95 void UrlBarTexture::SetHistoryButtonsEnabled(bool can_go_back) { |
| 137 if (can_go_back != can_go_back_) | 96 if (can_go_back != can_go_back_) |
| 138 set_dirty(); | 97 set_dirty(); |
| 139 can_go_back_ = can_go_back; | 98 can_go_back_ = can_go_back; |
| 140 } | 99 } |
| 141 | 100 |
| 142 void UrlBarTexture::SetSecurityInfo(SecurityLevel level, bool malware) { | |
| 143 if (security_level_ != level || malware_ != malware) | |
| 144 set_dirty(); | |
| 145 security_level_ = level; | |
| 146 malware_ = malware; | |
| 147 } | |
| 148 | |
| 149 float UrlBarTexture::ToPixels(float meters) const { | 101 float UrlBarTexture::ToPixels(float meters) const { |
| 150 return meters * size_.width() / kWidth; | 102 return meters * size_.width() / kWidth; |
| 151 } | 103 } |
| 152 | 104 |
| 153 float UrlBarTexture::ToMeters(float pixels) const { | 105 float UrlBarTexture::ToMeters(float pixels) const { |
| 154 return pixels * kWidth / size_.width(); | 106 return pixels * kWidth / size_.width(); |
| 155 } | 107 } |
| 156 | 108 |
| 157 bool UrlBarTexture::HitsBackButton(const gfx::PointF& position) const { | 109 bool UrlBarTexture::HitsBackButton(const gfx::PointF& position) const { |
| 158 const gfx::PointF& meters = percentToMeters(position); | 110 const gfx::PointF& meters = percentToMeters(position); |
| (...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 259 can_go_back_ ? color_scheme().element_foreground | 211 can_go_back_ ? color_scheme().element_foreground |
| 260 : color_scheme().disabled); | 212 : color_scheme().disabled); |
| 261 canvas->restore(); | 213 canvas->restore(); |
| 262 | 214 |
| 263 back_button_hit_region_.SetRect(left_edge, 0, left_edge + kBackButtonWidth, | 215 back_button_hit_region_.SetRect(left_edge, 0, left_edge + kBackButtonWidth, |
| 264 kHeight); | 216 kHeight); |
| 265 left_edge += kBackButtonWidth + kSeparatorWidth; | 217 left_edge += kBackButtonWidth + kSeparatorWidth; |
| 266 } | 218 } |
| 267 | 219 |
| 268 // Site security state icon. | 220 // Site security state icon. |
| 269 if (!gurl_.is_empty()) { | 221 left_edge += kFieldSpacing; |
| 270 left_edge += kFieldSpacing; | 222 if (state_.security_level != security_state::NONE && |
| 271 | 223 state_.vector_icon != nullptr) { |
| 272 gfx::RectF icon_region(left_edge, kHeight / 2 - kSecurityIconHeight / 2, | 224 gfx::RectF icon_region(left_edge, kHeight / 2 - kSecurityIconSize / 2, |
| 273 kSecurityIconHeight, kSecurityIconHeight); | 225 kSecurityIconSize, kSecurityIconSize); |
| 274 canvas->save(); | 226 canvas->save(); |
| 275 canvas->translate(icon_region.x(), icon_region.y()); | 227 canvas->translate(icon_region.x(), icon_region.y()); |
| 276 const gfx::VectorIcon& icon = GetSecurityIcon(security_level_); | 228 const gfx::VectorIcon& icon = *(state_.vector_icon); |
|
mthiesse
2017/06/28 00:27:08
nit: unnecessary parens
cjgrant
2017/06/28 15:14:33
Done.
| |
| 277 float icon_scale = kSecurityIconHeight / GetDefaultSizeOfVectorIcon(icon); | 229 float icon_scale = kSecurityIconSize / GetDefaultSizeOfVectorIcon(icon); |
| 278 canvas->scale(icon_scale, icon_scale); | 230 canvas->scale(icon_scale, icon_scale); |
| 279 PaintVectorIcon(&gfx_canvas, icon, | 231 PaintVectorIcon(&gfx_canvas, icon, |
| 280 GetSchemeColor(security_level_, color_scheme())); | 232 GetSchemeColor(state_.security_level, color_scheme())); |
| 281 canvas->restore(); | 233 canvas->restore(); |
| 282 | 234 |
| 283 security_hit_region_ = icon_region; | 235 security_hit_region_ = icon_region; |
| 284 left_edge += kSecurityIconHeight + kFieldSpacing; | 236 left_edge += kSecurityIconSize + kFieldSpacing; |
| 285 } | 237 } |
| 286 | 238 |
| 287 canvas->restore(); | 239 canvas->restore(); |
| 288 | 240 |
| 289 // Draw security chip text (eg. "Not secure") next to the security icon. | 241 // Draw security chip text (eg. "Not secure") next to the security icon. |
| 290 int chip_string_id = GetSecurityTextId(security_level_, malware_); | 242 if (has_security_chip_ && state_.should_display_url) { |
| 291 if (has_security_chip_ && !gurl_.is_empty() && chip_string_id != 0) { | |
| 292 float chip_max_width = kWidth - left_edge - kUrlRightMargin; | 243 float chip_max_width = kWidth - left_edge - kUrlRightMargin; |
| 293 gfx::Rect text_bounds(ToPixels(left_edge), 0, ToPixels(chip_max_width), | 244 gfx::Rect text_bounds(ToPixels(left_edge), 0, ToPixels(chip_max_width), |
| 294 ToPixels(kHeight)); | 245 ToPixels(kHeight)); |
| 295 | 246 |
| 296 int pixel_font_height = texture_size.height() * kFontHeight / kHeight; | 247 int pixel_font_height = texture_size.height() * kFontHeight / kHeight; |
| 297 SkColor chip_color = GetSchemeColor(security_level_, color_scheme()); | 248 SkColor chip_color = GetSchemeColor(state_.security_level, color_scheme()); |
| 298 auto chip_text = l10n_util::GetStringUTF16(chip_string_id); | 249 const base::string16& chip_text = state_.secure_verbose_text; |
| 299 DCHECK(!chip_text.empty()); | 250 DCHECK(!chip_text.empty()); |
| 300 | 251 |
| 301 gfx::FontList font_list; | 252 gfx::FontList font_list; |
| 302 if (!GetFontList(pixel_font_height, chip_text, &font_list)) | 253 if (!GetFontList(pixel_font_height, chip_text, &font_list)) |
| 303 failure_callback_.Run(UiUnsupportedMode::kUnhandledCodePoint); | 254 failure_callback_.Run(UiUnsupportedMode::kUnhandledCodePoint); |
| 304 | 255 |
| 305 std::unique_ptr<gfx::RenderText> render_text( | 256 std::unique_ptr<gfx::RenderText> render_text( |
| 306 gfx::RenderText::CreateInstance()); | 257 gfx::RenderText::CreateInstance()); |
| 307 render_text->SetFontList(font_list); | 258 render_text->SetFontList(font_list); |
| 308 render_text->SetColor(chip_color); | 259 render_text->SetColor(chip_color); |
| (...skipping 14 matching lines...) Expand all Loading... | |
| 323 left_edge += kFieldSpacing; | 274 left_edge += kFieldSpacing; |
| 324 paint.setColor(color_scheme().url_deemphasized); | 275 paint.setColor(color_scheme().url_deemphasized); |
| 325 canvas->drawRect( | 276 canvas->drawRect( |
| 326 SkRect::MakeXYWH(ToPixels(left_edge), ToPixels(kChipTextLineMargin), | 277 SkRect::MakeXYWH(ToPixels(left_edge), ToPixels(kChipTextLineMargin), |
| 327 ToPixels(kSeparatorWidth), | 278 ToPixels(kSeparatorWidth), |
| 328 ToPixels(kHeight - 2 * kChipTextLineMargin)), | 279 ToPixels(kHeight - 2 * kChipTextLineMargin)), |
| 329 paint); | 280 paint); |
| 330 left_edge += kFieldSpacing + kSeparatorWidth; | 281 left_edge += kFieldSpacing + kSeparatorWidth; |
| 331 } | 282 } |
| 332 | 283 |
| 333 if (!gurl_.is_empty()) { | 284 if (state_.should_display_url) { |
| 334 if (last_drawn_gurl_ != gurl_ || | 285 if (!url_render_text_ || last_drawn_gurl_ != state_.gurl || |
| 335 last_drawn_security_level_ != security_level_) { | 286 last_drawn_security_level_ != state_.security_level) { |
| 336 float url_x = left_edge; | 287 float url_x = left_edge; |
| 337 float url_width = kWidth - url_x - kUrlRightMargin; | 288 float url_width = kWidth - url_x - kUrlRightMargin; |
| 338 gfx::Rect text_bounds(ToPixels(url_x), 0, ToPixels(url_width), | 289 gfx::Rect text_bounds(ToPixels(url_x), 0, ToPixels(url_width), |
| 339 ToPixels(kHeight)); | 290 ToPixels(kHeight)); |
| 340 RenderUrl(texture_size, text_bounds); | 291 RenderUrl(texture_size, text_bounds); |
| 341 last_drawn_gurl_ = gurl_; | 292 last_drawn_gurl_ = state_.gurl; |
| 342 last_drawn_security_level_ = security_level_; | 293 last_drawn_security_level_ = state_.security_level; |
| 343 } | 294 } |
| 344 url_render_text_->Draw(&gfx_canvas); | 295 url_render_text_->Draw(&gfx_canvas); |
| 345 } | 296 } |
| 346 } | 297 } |
| 347 | 298 |
| 348 void UrlBarTexture::RenderUrl(const gfx::Size& texture_size, | 299 void UrlBarTexture::RenderUrl(const gfx::Size& texture_size, |
| 349 const gfx::Rect& bounds) { | 300 const gfx::Rect& bounds) { |
| 350 url::Parsed parsed; | 301 url::Parsed parsed; |
| 351 const base::string16 text = url_formatter::FormatUrl( | 302 const base::string16 text = url_formatter::FormatUrl( |
| 352 gurl_, url_formatter::kFormatUrlOmitAll, net::UnescapeRule::NORMAL, | 303 state_.gurl, url_formatter::kFormatUrlOmitAll, net::UnescapeRule::NORMAL, |
| 353 &parsed, nullptr, nullptr); | 304 &parsed, nullptr, nullptr); |
| 354 | 305 |
| 355 int pixel_font_height = texture_size.height() * kFontHeight / kHeight; | 306 int pixel_font_height = texture_size.height() * kFontHeight / kHeight; |
| 356 | 307 |
| 357 gfx::FontList font_list; | 308 gfx::FontList font_list; |
| 358 if (!GetFontList(pixel_font_height, text, &font_list)) | 309 if (!GetFontList(pixel_font_height, text, &font_list)) |
| 359 failure_callback_.Run(UiUnsupportedMode::kUnhandledCodePoint); | 310 failure_callback_.Run(UiUnsupportedMode::kUnhandledCodePoint); |
| 360 | 311 |
| 361 std::unique_ptr<gfx::RenderText> render_text( | 312 std::unique_ptr<gfx::RenderText> render_text( |
| 362 gfx::RenderText::CreateInstance()); | 313 gfx::RenderText::CreateInstance()); |
| (...skipping 14 matching lines...) Expand all Loading... | |
| 377 // Ellipsis-based eliding replaces the last character in the string with an | 328 // Ellipsis-based eliding replaces the last character in the string with an |
| 378 // ellipsis, so to reliably check that the origin is intact, check both length | 329 // ellipsis, so to reliably check that the origin is intact, check both length |
| 379 // and string equality. | 330 // and string equality. |
| 380 if (render_text->GetDisplayText().size() < mandatory_prefix.size() || | 331 if (render_text->GetDisplayText().size() < mandatory_prefix.size() || |
| 381 render_text->GetDisplayText().substr(0, mandatory_prefix.size()) != | 332 render_text->GetDisplayText().substr(0, mandatory_prefix.size()) != |
| 382 mandatory_prefix) { | 333 mandatory_prefix) { |
| 383 failure_callback_.Run(UiUnsupportedMode::kCouldNotElideURL); | 334 failure_callback_.Run(UiUnsupportedMode::kCouldNotElideURL); |
| 384 } | 335 } |
| 385 | 336 |
| 386 vr_shell::RenderTextWrapper vr_render_text(render_text.get()); | 337 vr_shell::RenderTextWrapper vr_render_text(render_text.get()); |
| 387 ApplyUrlStyling(text, parsed, security_level_, &vr_render_text, | 338 ApplyUrlStyling(text, parsed, state_.security_level, &vr_render_text, |
| 388 color_scheme()); | 339 color_scheme()); |
| 389 | 340 |
| 390 url_render_text_ = std::move(render_text); | 341 url_render_text_ = std::move(render_text); |
| 391 url_text_ = text; | 342 url_text_ = text; |
| 392 } | 343 } |
| 393 | 344 |
| 394 // This method replicates behavior in OmniboxView::UpdateTextStyle(), and | 345 // This method replicates behavior in OmniboxView::UpdateTextStyle(), and |
| 395 // attempts to maintain similar code structure. | 346 // attempts to maintain similar code structure. |
| 396 void UrlBarTexture::ApplyUrlStyling( | 347 void UrlBarTexture::ApplyUrlStyling( |
| 397 const base::string16& formatted_url, | 348 const base::string16& formatted_url, |
| (...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 459 | 410 |
| 460 gfx::Size UrlBarTexture::GetPreferredTextureSize(int maximum_width) const { | 411 gfx::Size UrlBarTexture::GetPreferredTextureSize(int maximum_width) const { |
| 461 return gfx::Size(maximum_width, maximum_width * kHeight / kWidth); | 412 return gfx::Size(maximum_width, maximum_width * kHeight / kWidth); |
| 462 } | 413 } |
| 463 | 414 |
| 464 gfx::SizeF UrlBarTexture::GetDrawnSize() const { | 415 gfx::SizeF UrlBarTexture::GetDrawnSize() const { |
| 465 return size_; | 416 return size_; |
| 466 } | 417 } |
| 467 | 418 |
| 468 } // namespace vr_shell | 419 } // namespace vr_shell |
| OLD | NEW |