OLD | NEW |
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 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 "content/shell/browser/shell.h" | 5 #include "content/shell/browser/shell.h" |
6 | 6 |
7 #include "base/command_line.h" | 7 #include "base/command_line.h" |
8 #include "base/strings/utf_string_conversions.h" | 8 #include "base/strings/utf_string_conversions.h" |
9 #include "content/public/browser/context_factory.h" | 9 #include "content/public/browser/context_factory.h" |
10 #include "content/public/browser/render_widget_host_view.h" | 10 #include "content/public/browser/render_widget_host_view.h" |
(...skipping 13 matching lines...) Expand all Loading... |
24 #include "ui/views/background.h" | 24 #include "ui/views/background.h" |
25 #include "ui/views/controls/button/label_button.h" | 25 #include "ui/views/controls/button/label_button.h" |
26 #include "ui/views/controls/button/menu_button.h" | 26 #include "ui/views/controls/button/menu_button.h" |
27 #include "ui/views/controls/button/menu_button_listener.h" | 27 #include "ui/views/controls/button/menu_button_listener.h" |
28 #include "ui/views/controls/menu/menu_runner.h" | 28 #include "ui/views/controls/menu/menu_runner.h" |
29 #include "ui/views/controls/textfield/textfield.h" | 29 #include "ui/views/controls/textfield/textfield.h" |
30 #include "ui/views/controls/textfield/textfield_controller.h" | 30 #include "ui/views/controls/textfield/textfield_controller.h" |
31 #include "ui/views/controls/webview/webview.h" | 31 #include "ui/views/controls/webview/webview.h" |
32 #include "ui/views/layout/fill_layout.h" | 32 #include "ui/views/layout/fill_layout.h" |
33 #include "ui/views/layout/grid_layout.h" | 33 #include "ui/views/layout/grid_layout.h" |
34 #include "ui/views/test/desktop_test_views_delegate.h" | |
35 #include "ui/views/view.h" | 34 #include "ui/views/view.h" |
36 #include "ui/views/widget/widget.h" | 35 #include "ui/views/widget/widget.h" |
37 #include "ui/views/widget/widget_delegate.h" | 36 #include "ui/views/widget/widget_delegate.h" |
38 | 37 |
39 #if defined(OS_CHROMEOS) | 38 #if defined(OS_CHROMEOS) |
40 #include "chromeos/dbus/dbus_thread_manager.h" | 39 #include "chromeos/dbus/dbus_thread_manager.h" |
41 #include "device/bluetooth/dbus/bluez_dbus_manager.h" | 40 #include "device/bluetooth/dbus/bluez_dbus_manager.h" |
| 41 #endif |
| 42 #if defined(OS_CHROMEOS) || defined(OS_ANDROID) |
42 #include "ui/aura/test/test_screen.h" | 43 #include "ui/aura/test/test_screen.h" |
43 #include "ui/wm/test/wm_test_helper.h" | 44 #include "ui/wm/test/wm_test_helper.h" |
44 #else // !defined(OS_CHROMEOS) | 45 #else // !defined(OS_CHROMEOS) && !defined(OS_ANDROID) |
45 #include "ui/views/widget/desktop_aura/desktop_screen.h" | 46 #include "ui/views/widget/desktop_aura/desktop_screen.h" |
46 #endif | 47 #endif |
47 | 48 |
48 #if defined(OS_WIN) | 49 #if defined(OS_WIN) |
49 #include <fcntl.h> | 50 #include <fcntl.h> |
50 #include <io.h> | 51 #include <io.h> |
51 #endif | 52 #endif |
52 | 53 |
| 54 #if defined(OS_ANDROID) |
| 55 #include "base/android/scoped_java_ref.h" |
| 56 #include "base/run_loop.h" |
| 57 #include "jni/Shell_jni.h" |
| 58 #include "ui/aura/client/aura_constants.h" |
| 59 #include "ui/views/test/test_views_delegate.h" |
| 60 #include "ui/views/widget/android/native_widget_android.h" |
| 61 #include "ui/views/widget/native_widget_aura.h" |
| 62 #else |
| 63 #include "ui/views/test/desktop_test_views_delegate.h" |
| 64 #endif |
| 65 |
| 66 #if defined(OS_ANDROID) |
| 67 using base::android::AttachCurrentThread; |
| 68 #endif |
| 69 |
53 namespace content { | 70 namespace content { |
54 | 71 |
55 namespace { | 72 namespace { |
| 73 |
| 74 struct GlobalState { |
| 75 GlobalState() {} |
| 76 base::android::ScopedJavaGlobalRef<jobject> j_shell; |
| 77 }; |
| 78 |
| 79 base::LazyInstance<GlobalState> g_global_state = LAZY_INSTANCE_INITIALIZER; |
| 80 |
56 // ViewDelegate implementation for aura content shell | 81 // ViewDelegate implementation for aura content shell |
| 82 #if defined(OS_ANDROID) |
| 83 class ShellViewsDelegateAura : public views::TestViewsDelegate { |
| 84 public: |
| 85 ShellViewsDelegateAura() : use_transparent_windows_(false) { |
| 86 } |
| 87 |
| 88 ~ShellViewsDelegateAura() override {} |
| 89 |
| 90 void SetUseTransparentWindows(bool transparent) { |
| 91 use_transparent_windows_ = transparent; |
| 92 } |
| 93 |
| 94 void OnBeforeWidgetInit( |
| 95 views::Widget::InitParams* params, |
| 96 views::internal::NativeWidgetDelegate* delegate) { |
| 97 #if !defined(OS_CHROMEOS) |
| 98 // If we already have a native_widget, we don't have to try to come |
| 99 // up with one. |
| 100 if (params->native_widget) |
| 101 return; |
| 102 |
| 103 if (params->parent && |
| 104 params->type != views::Widget::InitParams::TYPE_MENU && |
| 105 params->type != views::Widget::InitParams::TYPE_TOOLTIP) { |
| 106 params->native_widget = new views::NativeWidgetAura(delegate); |
| 107 } else { |
| 108 params->native_widget = new views::NativeWidgetAndroid(delegate); |
| 109 } |
| 110 #endif |
| 111 } |
| 112 |
| 113 private: |
| 114 bool use_transparent_windows_; |
| 115 |
| 116 DISALLOW_COPY_AND_ASSIGN(ShellViewsDelegateAura); |
| 117 }; |
| 118 #else |
57 class ShellViewsDelegateAura : public views::DesktopTestViewsDelegate { | 119 class ShellViewsDelegateAura : public views::DesktopTestViewsDelegate { |
58 public: | 120 public: |
59 ShellViewsDelegateAura() : use_transparent_windows_(false) { | 121 ShellViewsDelegateAura() : use_transparent_windows_(false) { |
60 } | 122 } |
61 | 123 |
62 ~ShellViewsDelegateAura() override {} | 124 ~ShellViewsDelegateAura() override {} |
63 | 125 |
64 void SetUseTransparentWindows(bool transparent) { | 126 void SetUseTransparentWindows(bool transparent) { |
65 use_transparent_windows_ = transparent; | 127 use_transparent_windows_ = transparent; |
66 } | 128 } |
67 | 129 |
68 private: | 130 private: |
69 bool use_transparent_windows_; | 131 bool use_transparent_windows_; |
70 | 132 |
71 DISALLOW_COPY_AND_ASSIGN(ShellViewsDelegateAura); | 133 DISALLOW_COPY_AND_ASSIGN(ShellViewsDelegateAura); |
72 }; | 134 }; |
| 135 #endif |
73 | 136 |
74 // Model for the "Debug" menu | 137 // Model for the "Debug" menu |
75 class ContextMenuModel : public ui::SimpleMenuModel, | 138 class ContextMenuModel : public ui::SimpleMenuModel, |
76 public ui::SimpleMenuModel::Delegate { | 139 public ui::SimpleMenuModel::Delegate { |
77 public: | 140 public: |
78 explicit ContextMenuModel( | 141 explicit ContextMenuModel( |
79 Shell* shell, const content::ContextMenuParams& params) | 142 Shell* shell, const content::ContextMenuParams& params) |
80 : ui::SimpleMenuModel(this), | 143 : ui::SimpleMenuModel(this), |
81 shell_(shell), | 144 shell_(shell), |
82 params_(params) { | 145 params_(params) { |
(...skipping 220 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
303 // Overridden from TextfieldController | 366 // Overridden from TextfieldController |
304 void ContentsChanged(views::Textfield* sender, | 367 void ContentsChanged(views::Textfield* sender, |
305 const base::string16& new_contents) override {} | 368 const base::string16& new_contents) override {} |
306 bool HandleKeyEvent(views::Textfield* sender, | 369 bool HandleKeyEvent(views::Textfield* sender, |
307 const ui::KeyEvent& key_event) override { | 370 const ui::KeyEvent& key_event) override { |
308 if (sender == url_entry_ && key_event.key_code() == ui::VKEY_RETURN) { | 371 if (sender == url_entry_ && key_event.key_code() == ui::VKEY_RETURN) { |
309 std::string text = base::UTF16ToUTF8(url_entry_->text()); | 372 std::string text = base::UTF16ToUTF8(url_entry_->text()); |
310 GURL url(text); | 373 GURL url(text); |
311 if (!url.has_scheme()) { | 374 if (!url.has_scheme()) { |
312 url = GURL(std::string("http://") + std::string(text)); | 375 url = GURL(std::string("http://") + std::string(text)); |
| 376 if (url.is_empty() || !url.is_valid()) |
| 377 return false; |
313 url_entry_->SetText(base::ASCIIToUTF16(url.spec())); | 378 url_entry_->SetText(base::ASCIIToUTF16(url.spec())); |
314 } | 379 } |
315 shell_->LoadURL(url); | 380 shell_->LoadURL(url); |
316 return true; | 381 return true; |
317 } | 382 } |
318 return false; | 383 return false; |
319 } | 384 } |
320 | 385 |
321 // Overridden from ButtonListener | 386 // Overridden from ButtonListener |
322 void ButtonPressed(views::Button* sender, const ui::Event& event) override { | 387 void ButtonPressed(views::Button* sender, const ui::Event& event) override { |
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
392 | 457 |
393 // Contents view contains the web contents view | 458 // Contents view contains the web contents view |
394 View* contents_view_; | 459 View* contents_view_; |
395 views::WebView* web_view_; | 460 views::WebView* web_view_; |
396 | 461 |
397 DISALLOW_COPY_AND_ASSIGN(ShellWindowDelegateView); | 462 DISALLOW_COPY_AND_ASSIGN(ShellWindowDelegateView); |
398 }; | 463 }; |
399 | 464 |
400 } // namespace | 465 } // namespace |
401 | 466 |
402 #if defined(OS_CHROMEOS) | 467 #if defined(OS_CHROMEOS) || defined(OS_ANDROID) |
403 wm::WMTestHelper* Shell::wm_test_helper_ = NULL; | 468 wm::WMTestHelper* Shell::wm_test_helper_ = NULL; |
404 gfx::Screen* Shell::test_screen_ = NULL; | 469 gfx::Screen* Shell::test_screen_ = NULL; |
405 #endif | 470 #endif |
406 views::ViewsDelegate* Shell::views_delegate_ = NULL; | 471 views::ViewsDelegate* Shell::views_delegate_ = NULL; |
407 | 472 |
408 // static | |
409 void Shell::PlatformInitialize(const gfx::Size& default_window_size) { | 473 void Shell::PlatformInitialize(const gfx::Size& default_window_size) { |
| 474 LOG(ERROR) << "auraclank: Shell::PlatformInitialize"; |
410 #if defined(OS_WIN) | 475 #if defined(OS_WIN) |
411 _setmode(_fileno(stdout), _O_BINARY); | 476 _setmode(_fileno(stdout), _O_BINARY); |
412 _setmode(_fileno(stderr), _O_BINARY); | 477 _setmode(_fileno(stderr), _O_BINARY); |
413 #endif | 478 #endif |
414 #if defined(OS_CHROMEOS) | 479 #if defined(OS_CHROMEOS) |
415 chromeos::DBusThreadManager::Initialize(); | 480 chromeos::DBusThreadManager::Initialize(); |
416 bluez::BluezDBusManager::Initialize( | 481 bluez::BluezDBusManager::Initialize( |
417 chromeos::DBusThreadManager::Get()->GetSystemBus(), | 482 chromeos::DBusThreadManager::Get()->GetSystemBus(), |
418 chromeos::DBusThreadManager::Get()->IsUsingStub( | 483 chromeos::DBusThreadManager::Get()->IsUsingStub( |
419 chromeos::DBusClientBundle::BLUETOOTH)); | 484 chromeos::DBusClientBundle::BLUETOOTH)); |
| 485 #endif |
| 486 #if defined(OS_CHROMEOS) || defined(OS_ANDROID) |
| 487 // TODO(mfomitchev): We can either use wm_test_helper_ here and have that instan
tiate |
| 488 // the host, or we can use the views delegate (which seems like a better approac
h). |
| 489 // TODO(mfomitchev): We should pick the screen we use on Android. |
| 490 // If we use screen_android, we shouldn't do this. |
420 test_screen_ = aura::TestScreen::Create(gfx::Size()); | 491 test_screen_ = aura::TestScreen::Create(gfx::Size()); |
421 gfx::Screen::SetScreenInstance(gfx::SCREEN_TYPE_NATIVE, test_screen_); | 492 gfx::Screen::SetScreenInstance(gfx::SCREEN_TYPE_NATIVE, test_screen_); |
| 493 JNIEnv* env = base::android::AttachCurrentThread(); |
| 494 jobject j_shell = g_global_state.Get().j_shell.obj(); |
| 495 jobject j_activity = Java_Shell_getActivity(env, j_shell).obj(); |
422 wm_test_helper_ = new wm::WMTestHelper(default_window_size, | 496 wm_test_helper_ = new wm::WMTestHelper(default_window_size, |
423 GetContextFactory()); | 497 GetContextFactory()); |
| 498 wm_test_helper_->host()->window()->SetProperty( |
| 499 aura::client::kActivityForRootWindow, j_activity); |
424 #else | 500 #else |
425 gfx::Screen::SetScreenInstance( | 501 gfx::Screen::SetScreenInstance( |
426 gfx::SCREEN_TYPE_NATIVE, views::CreateDesktopScreen()); | 502 gfx::SCREEN_TYPE_NATIVE, views::CreateDesktopScreen()); |
427 #endif | 503 #endif |
428 views_delegate_ = new ShellViewsDelegateAura(); | 504 views_delegate_ = new ShellViewsDelegateAura(); |
429 } | 505 } |
430 | 506 |
431 void Shell::PlatformExit() { | 507 void Shell::PlatformExit() { |
432 #if defined(OS_CHROMEOS) | 508 #if defined(OS_CHROMEOS) || defined(OS_ANDROID) |
433 delete wm_test_helper_; | 509 delete wm_test_helper_; |
434 wm_test_helper_ = NULL; | 510 wm_test_helper_ = NULL; |
435 | 511 |
436 delete test_screen_; | 512 delete test_screen_; |
437 test_screen_ = NULL; | 513 test_screen_ = NULL; |
438 #endif | 514 #endif |
439 delete views_delegate_; | 515 delete views_delegate_; |
440 views_delegate_ = NULL; | 516 views_delegate_ = NULL; |
441 delete platform_; | 517 delete platform_; |
442 platform_ = NULL; | 518 platform_ = NULL; |
443 #if defined(OS_CHROMEOS) | 519 #if defined(OS_CHROMEOS) |
444 device::BluetoothAdapterFactory::Shutdown(); | 520 device::BluetoothAdapterFactory::Shutdown(); |
445 bluez::BluezDBusManager::Shutdown(); | 521 bluez::BluezDBusManager::Shutdown(); |
446 chromeos::DBusThreadManager::Shutdown(); | 522 chromeos::DBusThreadManager::Shutdown(); |
447 #endif | 523 #endif |
448 aura::Env::DeleteInstance(); | 524 aura::Env::DeleteInstance(); |
449 } | 525 } |
450 | 526 |
451 void Shell::PlatformCleanUp() { | |
452 } | |
453 | |
454 void Shell::PlatformEnableUIControl(UIControl control, bool is_enabled) { | 527 void Shell::PlatformEnableUIControl(UIControl control, bool is_enabled) { |
455 if (headless_) | 528 if (headless_) |
456 return; | 529 return; |
457 ShellWindowDelegateView* delegate_view = | 530 ShellWindowDelegateView* delegate_view = |
458 static_cast<ShellWindowDelegateView*>(window_widget_->widget_delegate()); | 531 static_cast<ShellWindowDelegateView*>(window_widget_->widget_delegate()); |
459 if (control == BACK_BUTTON) { | 532 if (control == BACK_BUTTON) { |
460 delegate_view->EnableUIControl(ShellWindowDelegateView::BACK_BUTTON, | 533 delegate_view->EnableUIControl(ShellWindowDelegateView::BACK_BUTTON, |
461 is_enabled); | 534 is_enabled); |
462 } else if (control == FORWARD_BUTTON) { | 535 } else if (control == FORWARD_BUTTON) { |
463 delegate_view->EnableUIControl(ShellWindowDelegateView::FORWARD_BUTTON, | 536 delegate_view->EnableUIControl(ShellWindowDelegateView::FORWARD_BUTTON, |
464 is_enabled); | 537 is_enabled); |
465 } else if (control == STOP_BUTTON) { | 538 } else if (control == STOP_BUTTON) { |
466 delegate_view->EnableUIControl(ShellWindowDelegateView::STOP_BUTTON, | 539 delegate_view->EnableUIControl(ShellWindowDelegateView::STOP_BUTTON, |
467 is_enabled); | 540 is_enabled); |
468 } | 541 } |
469 } | 542 } |
470 | 543 |
471 void Shell::PlatformSetAddressBarURL(const GURL& url) { | 544 void Shell::PlatformSetAddressBarURL(const GURL& url) { |
472 if (headless_) | 545 if (headless_) |
473 return; | 546 return; |
474 ShellWindowDelegateView* delegate_view = | 547 ShellWindowDelegateView* delegate_view = |
475 static_cast<ShellWindowDelegateView*>(window_widget_->widget_delegate()); | 548 static_cast<ShellWindowDelegateView*>(window_widget_->widget_delegate()); |
476 delegate_view->SetAddressBarURL(url); | 549 delegate_view->SetAddressBarURL(url); |
477 } | 550 } |
478 | 551 |
479 void Shell::PlatformSetIsLoading(bool loading) { | 552 void Shell::PlatformSetIsLoading(bool loading) { |
480 } | 553 } |
481 | 554 |
482 void Shell::PlatformCreateWindow(int width, int height) { | 555 void Shell::PlatformCreateWindow(int width, int height) { |
| 556 LOG(ERROR) << "auraclank: Shell::PlatformCreateWindow"; |
483 if (headless_) { | 557 if (headless_) { |
484 content_size_ = gfx::Size(width, height); | 558 content_size_ = gfx::Size(width, height); |
485 if (!platform_) | 559 if (!platform_) |
486 platform_ = new ShellPlatformDataAura(content_size_); | 560 platform_ = new ShellPlatformDataAura(content_size_); |
487 else | 561 else |
488 platform_->ResizeWindow(content_size_); | 562 platform_->ResizeWindow(content_size_); |
489 return; | 563 return; |
490 } | 564 } |
491 #if defined(OS_CHROMEOS) | 565 |
| 566 #if defined(OS_CHROMEOS) || defined(OS_ANDROID) |
| 567 wm_test_helper_->Init(); |
492 window_widget_ = views::Widget::CreateWindowWithContextAndBounds( | 568 window_widget_ = views::Widget::CreateWindowWithContextAndBounds( |
493 new ShellWindowDelegateView(this), | 569 new ShellWindowDelegateView(this), |
494 wm_test_helper_->GetDefaultParent(NULL, NULL, gfx::Rect()), | 570 wm_test_helper_->GetDefaultParent(NULL, NULL, gfx::Rect()), |
495 gfx::Rect(0, 0, width, height)); | 571 gfx::Rect(0, 0, width, height)); |
496 #else | 572 #else |
497 window_widget_ = new views::Widget; | 573 window_widget_ = new views::Widget; |
498 views::Widget::InitParams params; | 574 views::Widget::InitParams params; |
499 params.bounds = gfx::Rect(0, 0, width, height); | 575 params.bounds = gfx::Rect(0, 0, width, height); |
500 params.delegate = new ShellWindowDelegateView(this); | 576 params.delegate = new ShellWindowDelegateView(this); |
501 window_widget_->Init(params); | 577 window_widget_->Init(params); |
502 #endif | 578 #endif |
503 | 579 |
504 content_size_ = gfx::Size(width, height); | 580 content_size_ = gfx::Size(width, height); |
505 | 581 |
506 window_ = window_widget_->GetNativeWindow(); | 582 window_ = window_widget_->GetNativeWindow(); |
507 // Call ShowRootWindow on RootWindow created by WMTestHelper without | 583 // Call ShowRootWindow on RootWindow created by WMTestHelper without |
508 // which XWindow owned by RootWindow doesn't get mapped. | 584 // which XWindow owned by RootWindow doesn't get mapped. |
| 585 //TODO(mfomitchev) |
509 window_->GetHost()->Show(); | 586 window_->GetHost()->Show(); |
510 window_widget_->Show(); | 587 window_widget_->Show(); |
| 588 |
| 589 |
511 } | 590 } |
512 | 591 |
| 592 #if defined(OS_ANDROID) |
| 593 // aura::EnvObserver: |
| 594 void Shell::OnHostInitialized(aura::WindowTreeHost* host) { |
| 595 LOG(ERROR) << "auraclank: Shell::OnHostInitialized!"; |
| 596 // quit_closure_.Run(); |
| 597 aura::Env::GetInstance()->RemoveObserver(this); |
| 598 } |
| 599 #endif |
| 600 |
| 601 |
513 void Shell::PlatformSetContents() { | 602 void Shell::PlatformSetContents() { |
514 if (headless_) { | 603 if (headless_) { |
515 CHECK(platform_); | 604 CHECK(platform_); |
516 aura::Window* content = web_contents_->GetNativeView(); | 605 aura::Window* content = web_contents_->GetNativeView(); |
517 aura::Window* parent = platform_->host()->window(); | 606 aura::Window* parent = platform_->host()->window(); |
518 if (!parent->Contains(content)) { | 607 if (!parent->Contains(content)) { |
519 parent->AddChild(content); | 608 parent->AddChild(content); |
520 content->Show(); | 609 content->Show(); |
521 } | 610 } |
522 content->SetBounds(gfx::Rect(content_size_)); | 611 content->SetBounds(gfx::Rect(content_size_)); |
(...skipping 30 matching lines...) Expand all Loading... |
553 bool Shell::PlatformHandleContextMenu( | 642 bool Shell::PlatformHandleContextMenu( |
554 const content::ContextMenuParams& params) { | 643 const content::ContextMenuParams& params) { |
555 if (headless_) | 644 if (headless_) |
556 return true; | 645 return true; |
557 ShellWindowDelegateView* delegate_view = | 646 ShellWindowDelegateView* delegate_view = |
558 static_cast<ShellWindowDelegateView*>(window_widget_->widget_delegate()); | 647 static_cast<ShellWindowDelegateView*>(window_widget_->widget_delegate()); |
559 delegate_view->ShowWebViewContextMenu(params); | 648 delegate_view->ShowWebViewContextMenu(params); |
560 return true; | 649 return true; |
561 } | 650 } |
562 | 651 |
| 652 #if defined(OS_ANDROID) |
| 653 // static |
| 654 bool Shell::Register(JNIEnv* env) { |
| 655 return RegisterNativesImpl(env); |
| 656 } |
| 657 |
| 658 // static |
| 659 void CloseShell( |
| 660 JNIEnv* env, const JavaParamRef<jclass>& clazz, jlong shellPtr) { |
| 661 Shell* shell = reinterpret_cast<Shell*>(shellPtr); |
| 662 shell->Close(); |
| 663 } |
| 664 |
| 665 static void Init(JNIEnv* env, |
| 666 const JavaParamRef<jclass>& clazz, |
| 667 const JavaParamRef<jobject>& obj) { |
| 668 g_global_state.Get().j_shell.Reset(obj); |
| 669 } |
| 670 |
| 671 void Shell::PlatformCleanUp() { |
| 672 JNIEnv* env = AttachCurrentThread(); |
| 673 Java_Shell_onNativeDestroyed(env, g_global_state.Get().j_shell.obj()); |
| 674 } |
| 675 #endif |
| 676 |
| 677 |
563 } // namespace content | 678 } // namespace content |
OLD | NEW |