| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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/ui/views/search_view_controller.h" | 5 #include "chrome/browser/ui/views/search_view_controller.h" |
| 6 | 6 |
| 7 #include "chrome/browser/ui/search/search_model.h" | 7 #include "chrome/browser/ui/search/search_model.h" |
| 8 #include "chrome/browser/ui/search/search_tab_helper.h" | 8 #include "chrome/browser/ui/search/search_tab_helper.h" |
| 9 #include "chrome/browser/ui/search/search_types.h" | 9 #include "chrome/browser/ui/search/search_types.h" |
| 10 #include "chrome/browser/ui/search/search_ui.h" | 10 #include "chrome/browser/ui/search/search_ui.h" |
| 11 #include "chrome/browser/ui/tab_contents/tab_contents.h" | 11 #include "chrome/browser/ui/tab_contents/tab_contents.h" |
| 12 #include "chrome/browser/ui/views/frame/contents_container.h" | 12 #include "chrome/browser/ui/views/frame/contents_container.h" |
| 13 #include "chrome/browser/ui/views/location_bar/location_bar_container.h" | 13 #include "chrome/browser/ui/views/location_bar/location_bar_container.h" |
| 14 #include "chrome/browser/ui/webui/instant_ui.h" | 14 #include "chrome/browser/ui/webui/instant_ui.h" |
| 15 #include "chrome/common/url_constants.h" |
| 15 #include "grit/theme_resources.h" | 16 #include "grit/theme_resources.h" |
| 16 #include "ui/compositor/layer.h" | 17 #include "ui/compositor/layer.h" |
| 17 #include "ui/compositor/scoped_layer_animation_settings.h" | 18 #include "ui/compositor/scoped_layer_animation_settings.h" |
| 18 #include "ui/base/resource/resource_bundle.h" | 19 #include "ui/base/resource/resource_bundle.h" |
| 19 #include "ui/gfx/canvas.h" | 20 #include "ui/gfx/canvas.h" |
| 21 #include "ui/views/controls/webview/webview.h" |
| 20 #include "ui/views/layout/fill_layout.h" | 22 #include "ui/views/layout/fill_layout.h" |
| 21 #include "ui/views/layout/layout_manager.h" | 23 #include "ui/views/layout/layout_manager.h" |
| 22 | 24 |
| 25 #if defined(USE_AURA) |
| 26 #include "ui/aura/window.h" |
| 27 #endif |
| 28 |
| 23 namespace { | 29 namespace { |
| 24 | 30 |
| 31 // Stacks view's layer above all its sibling layers. |
| 32 void StackViewsLayerAtTop(views::View* view) { |
| 33 DCHECK(view->layer()); |
| 34 DCHECK(view->layer()->parent()); |
| 35 view->layer()->parent()->StackAtTop(view->layer()); |
| 36 } |
| 37 |
| 38 // Stacks native view's layer above all its sibling layers. |
| 39 void StackWebViewLayerAtTop(views::WebView* view) { |
| 40 if (!view->web_contents()) |
| 41 return; |
| 42 |
| 43 ui::Layer* native_view_layer = view->web_contents()->GetNativeView()->layer(); |
| 44 native_view_layer->parent()->StackAtTop(native_view_layer); |
| 45 } |
| 46 |
| 25 // SearchContainerView --------------------------------------------------------- | 47 // SearchContainerView --------------------------------------------------------- |
| 26 | 48 |
| 27 // SearchContainerView contains the |ntp_view_| and | 49 // SearchContainerView contains the |ntp_view_| and |
| 28 // |omnibox_popup_view_parent_|. |ntp_view_| is given the full size and | 50 // |omnibox_popup_view_parent_|. |ntp_view_| is given the full size and |
| 29 // the |omnibox_popup_view_parent_| is gives its preferred height. | 51 // the |omnibox_popup_view_parent_| is gives its preferred height. |
| 30 class SearchContainerView : public views::View { | 52 class SearchContainerView : public views::View { |
| 31 public: | 53 public: |
| 32 SearchContainerView(views::View* ntp_view, | 54 SearchContainerView(views::View* ntp_view, |
| 33 views::View* omnibox_popup_view_parent) | 55 views::View* omnibox_popup_view_parent) |
| 34 : ntp_view_(ntp_view), | 56 : ntp_view_(ntp_view), |
| (...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 119 | 141 |
| 120 private: | 142 private: |
| 121 DISALLOW_COPY_AND_ASSIGN(NTPViewBackground); | 143 DISALLOW_COPY_AND_ASSIGN(NTPViewBackground); |
| 122 }; | 144 }; |
| 123 | 145 |
| 124 // NTPViewLayoutManager -------------------------------------------------------- | 146 // NTPViewLayoutManager -------------------------------------------------------- |
| 125 | 147 |
| 126 // LayoutManager for the NTPView. | 148 // LayoutManager for the NTPView. |
| 127 class NTPViewLayoutManager : public views::LayoutManager { | 149 class NTPViewLayoutManager : public views::LayoutManager { |
| 128 public: | 150 public: |
| 129 NTPViewLayoutManager(views::View* logo_view, views::View* content_view) | 151 NTPViewLayoutManager(views::View* logo_view, views::WebView* content_view) |
| 130 : logo_view_(logo_view), | 152 : logo_view_(logo_view), |
| 131 content_view_(content_view) { | 153 content_view_(content_view) { |
| 132 } | 154 } |
| 133 virtual ~NTPViewLayoutManager() {} | 155 virtual ~NTPViewLayoutManager() {} |
| 134 | 156 |
| 135 // views::LayoutManager overrides: | 157 // views::LayoutManager overrides: |
| 136 virtual void Layout(views::View* host) OVERRIDE { | 158 virtual void Layout(views::View* host) OVERRIDE { |
| 137 gfx::Size logo_pref = logo_view_->GetPreferredSize(); | 159 gfx::Size logo_pref = logo_view_->GetPreferredSize(); |
| 138 logo_view_->SetBounds( | 160 logo_view_->SetBounds( |
| 139 (host->width() - logo_pref.width()) / 2, | 161 (host->width() - logo_pref.width()) / 2, |
| 140 chrome::search::kOmniboxYPosition - 20 - logo_pref.height(), | 162 chrome::search::kOmniboxYPosition - 20 - logo_pref.height(), |
| 141 logo_pref.width(), | 163 logo_pref.width(), |
| 142 logo_pref.height()); | 164 logo_pref.height()); |
| 143 | 165 |
| 144 gfx::Size content_pref(content_view_->GetPreferredSize()); | 166 const int kContentTop = chrome::search::kOmniboxYPosition + 50; |
| 145 int content_y = std::max(chrome::search::kOmniboxYPosition + 50, | 167 content_view_->SetBounds(0, |
| 146 host->height() - content_pref.height() - 50); | 168 kContentTop, |
| 147 content_view_->SetBounds((host->width() - content_pref.width()) / 2, | 169 host->width(), |
| 148 content_y, content_pref.width(), | 170 host->height() - kContentTop); |
| 149 content_pref.height()); | 171 |
| 172 // TODO(dhollowa): This is a hack to patch up ordering of native layer. |
| 173 // Changes to the view hierarchy can |ReorderLayers| which messes with |
| 174 // layer stacking. Layout typically follows reorderings, so we patch |
| 175 // things up here. |
| 176 StackWebViewLayerAtTop(content_view_); |
| 150 } | 177 } |
| 151 | 178 |
| 152 virtual gfx::Size GetPreferredSize(views::View* host) OVERRIDE { | 179 virtual gfx::Size GetPreferredSize(views::View* host) OVERRIDE { |
| 153 // Preferred size doesn't matter for the NTPView. | 180 // Preferred size doesn't matter for the NTPView. |
| 154 return gfx::Size(); | 181 return gfx::Size(); |
| 155 } | 182 } |
| 156 | 183 |
| 157 private: | 184 private: |
| 158 views::View* logo_view_; | 185 views::View* logo_view_; |
| 159 views::View* content_view_; | 186 views::WebView* content_view_; |
| 160 | 187 |
| 161 DISALLOW_COPY_AND_ASSIGN(NTPViewLayoutManager); | 188 DISALLOW_COPY_AND_ASSIGN(NTPViewLayoutManager); |
| 162 }; | 189 }; |
| 163 | 190 |
| 164 // Stacks view's layer above all its sibling layers. | |
| 165 void StackViewsLayerAtTop(views::View* view) { | |
| 166 DCHECK(view->layer()); | |
| 167 DCHECK(view->layer()->parent()); | |
| 168 view->layer()->parent()->StackAtTop(view->layer()); | |
| 169 } | |
| 170 | |
| 171 } // namespace | 191 } // namespace |
| 172 | 192 |
| 173 // SearchViewController::OmniboxPopupViewParent -------------------------------- | 193 // SearchViewController::OmniboxPopupViewParent -------------------------------- |
| 174 | 194 |
| 175 // View the omnibox is added to. Listens for changes to the visibility of the | 195 // View the omnibox is added to. Listens for changes to the visibility of the |
| 176 // omnibox and updates the SearchViewController appropriately. | 196 // omnibox and updates the SearchViewController appropriately. |
| 177 class SearchViewController::OmniboxPopupViewParent : public views::View { | 197 class SearchViewController::OmniboxPopupViewParent : public views::View { |
| 178 public: | 198 public: |
| 179 explicit OmniboxPopupViewParent(SearchViewController* search_view_controller); | 199 explicit OmniboxPopupViewParent(SearchViewController* search_view_controller); |
| 180 virtual ~OmniboxPopupViewParent(); | 200 virtual ~OmniboxPopupViewParent(); |
| (...skipping 28 matching lines...) Expand all Loading... |
| 209 parent()->Layout(); | 229 parent()->Layout(); |
| 210 if (child_visible_ != child->visible()) { | 230 if (child_visible_ != child->visible()) { |
| 211 child_visible_ = child->visible(); | 231 child_visible_ = child->visible(); |
| 212 search_view_controller_->PopupVisibilityChanged(); | 232 search_view_controller_->PopupVisibilityChanged(); |
| 213 } | 233 } |
| 214 } | 234 } |
| 215 | 235 |
| 216 // SearchViewController -------------------------------------------------------- | 236 // SearchViewController -------------------------------------------------------- |
| 217 | 237 |
| 218 SearchViewController::SearchViewController( | 238 SearchViewController::SearchViewController( |
| 239 content::BrowserContext* browser_context, |
| 219 ContentsContainer* contents_container) | 240 ContentsContainer* contents_container) |
| 220 : contents_container_(contents_container), | 241 : browser_context_(browser_context), |
| 242 contents_container_(contents_container), |
| 221 location_bar_container_(NULL), | 243 location_bar_container_(NULL), |
| 222 state_(STATE_NOT_VISIBLE), | 244 state_(STATE_NOT_VISIBLE), |
| 223 tab_(NULL), | 245 tab_contents_(NULL), |
| 224 search_container_(NULL), | 246 search_container_(NULL), |
| 225 ntp_view_(NULL), | 247 ntp_view_(NULL), |
| 226 logo_view_(NULL), | 248 logo_view_(NULL), |
| 227 content_view_(NULL), | 249 content_view_(NULL), |
| 228 omnibox_popup_view_parent_(NULL) { | 250 omnibox_popup_view_parent_(NULL) { |
| 229 omnibox_popup_view_parent_ = new OmniboxPopupViewParent(this); | 251 omnibox_popup_view_parent_ = new OmniboxPopupViewParent(this); |
| 230 } | 252 } |
| 231 | 253 |
| 232 SearchViewController::~SearchViewController() { | 254 SearchViewController::~SearchViewController() { |
| 233 if (search_model()) | 255 if (search_model()) |
| 234 search_model()->RemoveObserver(this); | 256 search_model()->RemoveObserver(this); |
| 235 | 257 |
| 236 // If the |omnibox_popup_view_| isn't parented, delete it. Otherwise it'll be | 258 // If the |omnibox_popup_view_| isn't parented, delete it. Otherwise it'll be |
| 237 // deleted by its parent. | 259 // deleted by its parent. |
| 238 if (!omnibox_popup_view_parent_->parent()) | 260 if (!omnibox_popup_view_parent_->parent()) |
| 239 delete omnibox_popup_view_parent_; | 261 delete omnibox_popup_view_parent_; |
| 240 } | 262 } |
| 241 | 263 |
| 242 views::View* SearchViewController::omnibox_popup_view_parent() { | 264 views::View* SearchViewController::omnibox_popup_view_parent() { |
| 243 return omnibox_popup_view_parent_; | 265 return omnibox_popup_view_parent_; |
| 244 } | 266 } |
| 245 | 267 |
| 246 void SearchViewController::SetTabContents(TabContents* tab) { | 268 void SearchViewController::SetTabContents(TabContents* tab_contents) { |
| 247 if (tab_ == tab) | 269 if (tab_contents_ == tab_contents) |
| 248 return; | 270 return; |
| 249 | 271 |
| 250 if (search_model()) | 272 if (search_model()) |
| 251 search_model()->RemoveObserver(this); | 273 search_model()->RemoveObserver(this); |
| 252 tab_ = tab; | 274 tab_contents_ = tab_contents; |
| 253 if (search_model()) | 275 if (search_model()) |
| 254 search_model()->AddObserver(this); | 276 search_model()->AddObserver(this); |
| 255 | 277 |
| 256 UpdateState(); | 278 UpdateState(); |
| 257 } | 279 } |
| 258 | 280 |
| 259 void SearchViewController::StackAtTop() { | 281 void SearchViewController::StackAtTop() { |
| 260 #if defined(USE_AURA) | 282 #if defined(USE_AURA) |
| 261 if (search_container_) { | 283 if (search_container_) { |
| 262 StackViewsLayerAtTop(search_container_); | 284 StackViewsLayerAtTop(search_container_); |
| 263 StackViewsLayerAtTop(ntp_view_); | 285 StackViewsLayerAtTop(ntp_view_); |
| 264 StackViewsLayerAtTop(logo_view_); | 286 StackViewsLayerAtTop(logo_view_); |
| 265 StackViewsLayerAtTop(content_view_); | 287 StackWebViewLayerAtTop(content_view_); |
| 266 } | 288 } |
| 267 #else | 289 #else |
| 268 NOTIMPLEMENTED(); | 290 NOTIMPLEMENTED(); |
| 269 #endif | 291 #endif |
| 270 location_bar_container_->StackAtTop(); | 292 location_bar_container_->StackAtTop(); |
| 271 } | 293 } |
| 272 | 294 |
| 273 void SearchViewController::InstantReady() { | 295 void SearchViewController::InstantReady() { |
| 274 } | 296 } |
| 275 | 297 |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 327 State old_state = state_; | 349 State old_state = state_; |
| 328 state_ = state; | 350 state_ = state; |
| 329 switch (state_) { | 351 switch (state_) { |
| 330 case STATE_NOT_VISIBLE: | 352 case STATE_NOT_VISIBLE: |
| 331 DestroyViews(); | 353 DestroyViews(); |
| 332 break; | 354 break; |
| 333 | 355 |
| 334 case STATE_NTP: | 356 case STATE_NTP: |
| 335 DestroyViews(); | 357 DestroyViews(); |
| 336 CreateViews(); | 358 CreateViews(); |
| 359 // TODO(dhollowa): This is temporary. The |content_view_| should pull its |
| 360 // web contents from the current tab's |search_tab_helper|. |
| 361 content_view_->LoadInitialURL(GURL(chrome::kChromeUINewTabURL)); |
| 337 break; | 362 break; |
| 338 | 363 |
| 339 case STATE_ANIMATING: | 364 case STATE_ANIMATING: |
| 340 // Should only animate from the ntp. | 365 // Should only animate from the ntp. |
| 341 DCHECK_EQ(STATE_NTP, old_state); | 366 DCHECK_EQ(STATE_NTP, old_state); |
| 342 StartAnimation(); | 367 StartAnimation(); |
| 343 break; | 368 break; |
| 344 | 369 |
| 345 case STATE_SEARCH: | 370 case STATE_SEARCH: |
| 346 DestroyViews(); | 371 DestroyViews(); |
| (...skipping 23 matching lines...) Expand all Loading... |
| 370 settings.SetTransitionDuration( | 395 settings.SetTransitionDuration( |
| 371 base::TimeDelta::FromMilliseconds(135 * factor)); | 396 base::TimeDelta::FromMilliseconds(135 * factor)); |
| 372 settings.SetTweenType(ui::Tween::EASE_IN_OUT); | 397 settings.SetTweenType(ui::Tween::EASE_IN_OUT); |
| 373 gfx::Rect bounds(logo_layer->bounds()); | 398 gfx::Rect bounds(logo_layer->bounds()); |
| 374 bounds.set_y(bounds.y() - 100); | 399 bounds.set_y(bounds.y() - 100); |
| 375 logo_layer->SetBounds(bounds); | 400 logo_layer->SetBounds(bounds); |
| 376 logo_layer->SetOpacity(0.0f); | 401 logo_layer->SetOpacity(0.0f); |
| 377 } | 402 } |
| 378 | 403 |
| 379 { | 404 { |
| 380 ui::Layer* content_layer = content_view_->layer(); | 405 ui::Layer* content_layer = |
| 406 content_view_->web_contents()->GetNativeView()->layer(); |
| 381 ui::ScopedLayerAnimationSettings settings(content_layer->GetAnimator()); | 407 ui::ScopedLayerAnimationSettings settings(content_layer->GetAnimator()); |
| 382 settings.SetTransitionDuration( | 408 settings.SetTransitionDuration( |
| 383 base::TimeDelta::FromMilliseconds(180 * factor)); | 409 base::TimeDelta::FromMilliseconds(180 * factor)); |
| 384 settings.SetTweenType(ui::Tween::LINEAR); | 410 settings.SetTweenType(ui::Tween::LINEAR); |
| 385 gfx::Rect bounds(content_layer->bounds()); | 411 gfx::Rect bounds(content_layer->bounds()); |
| 386 bounds.set_y(bounds.y() - 250); | 412 bounds.set_y(bounds.y() - 250); |
| 387 content_layer->SetBounds(bounds); | 413 content_layer->SetBounds(bounds); |
| 388 content_layer->SetOpacity(0.0f); | 414 content_layer->SetOpacity(0.0f); |
| 389 } | 415 } |
| 390 } | 416 } |
| 391 | 417 |
| 392 void SearchViewController::CreateViews() { | 418 void SearchViewController::CreateViews() { |
| 393 DCHECK(!ntp_view_); | 419 DCHECK(!ntp_view_); |
| 394 | 420 |
| 395 ntp_view_ = new views::View; | 421 ntp_view_ = new views::View; |
| 396 ntp_view_->set_background(new NTPViewBackground); | 422 ntp_view_->set_background(new NTPViewBackground); |
| 397 ntp_view_->SetPaintToLayer(true); | 423 ntp_view_->SetPaintToLayer(true); |
| 398 ntp_view_->layer()->SetMasksToBounds(true); | 424 ntp_view_->layer()->SetMasksToBounds(true); |
| 399 | 425 |
| 400 logo_view_ = new views::View; | 426 logo_view_ = new views::View; |
| 401 logo_view_->SetLayoutManager( | 427 logo_view_->SetLayoutManager( |
| 402 new FixedSizeLayoutManager(gfx::Size(300, 200))); | 428 new FixedSizeLayoutManager(gfx::Size(300, 200))); |
| 403 logo_view_->set_background( | 429 logo_view_->set_background( |
| 404 views::Background::CreateSolidBackground(SK_ColorRED)); | 430 views::Background::CreateSolidBackground(SK_ColorRED)); |
| 405 logo_view_->SetPaintToLayer(true); | 431 logo_view_->SetPaintToLayer(true); |
| 406 logo_view_->SetFillsBoundsOpaquely(false); | 432 logo_view_->SetFillsBoundsOpaquely(false); |
| 407 | 433 |
| 408 // TODO: replace with WebContents for NTP. | 434 content_view_ = new views::WebView(browser_context_); |
| 409 content_view_ = new views::View; | |
| 410 content_view_->SetLayoutManager( | |
| 411 new FixedSizeLayoutManager(gfx::Size(400, 200))); | |
| 412 content_view_->set_background( | |
| 413 views::Background::CreateSolidBackground(SK_ColorBLUE)); | |
| 414 content_view_->SetPaintToLayer(true); | |
| 415 content_view_->SetFillsBoundsOpaquely(false); | 435 content_view_->SetFillsBoundsOpaquely(false); |
| 416 | 436 |
| 417 ntp_view_->SetLayoutManager( | 437 ntp_view_->SetLayoutManager( |
| 418 new NTPViewLayoutManager(logo_view_, content_view_)); | 438 new NTPViewLayoutManager(logo_view_, content_view_)); |
| 439 ntp_view_->AddChildView(logo_view_); |
| 440 ntp_view_->AddChildView(content_view_); |
| 419 | 441 |
| 420 search_container_ = | 442 search_container_ = |
| 421 new SearchContainerView(ntp_view_, omnibox_popup_view_parent_); | 443 new SearchContainerView(ntp_view_, omnibox_popup_view_parent_); |
| 422 search_container_->SetPaintToLayer(true); | 444 search_container_->SetPaintToLayer(true); |
| 423 search_container_->SetLayoutManager(new views::FillLayout); | 445 search_container_->SetLayoutManager(new views::FillLayout); |
| 424 search_container_->layer()->SetMasksToBounds(true); | 446 search_container_->layer()->SetMasksToBounds(true); |
| 425 | 447 |
| 426 ntp_view_->AddChildView(logo_view_); | |
| 427 ntp_view_->AddChildView(content_view_); | |
| 428 | |
| 429 contents_container_->SetOverlay(search_container_); | 448 contents_container_->SetOverlay(search_container_); |
| 430 } | 449 } |
| 431 | 450 |
| 432 void SearchViewController::DestroyViews() { | 451 void SearchViewController::DestroyViews() { |
| 433 if (!search_container_) | 452 if (!search_container_) |
| 434 return; | 453 return; |
| 435 | 454 |
| 436 // We persist the parent of the omnibox so that we don't have to inject a new | 455 // We persist the parent of the omnibox so that we don't have to inject a new |
| 437 // parent into ToolbarView. | 456 // parent into ToolbarView. |
| 438 omnibox_popup_view_parent_->parent()->RemoveChildView( | 457 omnibox_popup_view_parent_->parent()->RemoveChildView( |
| 439 omnibox_popup_view_parent_); | 458 omnibox_popup_view_parent_); |
| 440 | 459 |
| 441 contents_container_->SetOverlay(NULL); | 460 contents_container_->SetOverlay(NULL); |
| 442 delete search_container_; | 461 delete search_container_; |
| 443 search_container_ = ntp_view_ = NULL; | 462 search_container_ = NULL; |
| 444 content_view_ = logo_view_ = NULL; | 463 ntp_view_ = NULL; |
| 464 logo_view_ = NULL; |
| 465 content_view_ = NULL; |
| 445 | 466 |
| 446 state_ = STATE_NOT_VISIBLE; | 467 state_ = STATE_NOT_VISIBLE; |
| 447 } | 468 } |
| 448 | 469 |
| 449 void SearchViewController::PopupVisibilityChanged() { | 470 void SearchViewController::PopupVisibilityChanged() { |
| 450 // Don't do anything while animating if the child is visible. Otherwise we'll | 471 // Don't do anything while animating if the child is visible. Otherwise we'll |
| 451 // prematurely cancel the animation. | 472 // prematurely cancel the animation. |
| 452 if (state_ != STATE_ANIMATING || | 473 if (state_ != STATE_ANIMATING || |
| 453 !omnibox_popup_view_parent_->is_child_visible()) { | 474 !omnibox_popup_view_parent_->is_child_visible()) { |
| 454 UpdateState(); | 475 UpdateState(); |
| 455 } | 476 } |
| 456 } | 477 } |
| 457 | 478 |
| 458 chrome::search::SearchModel* SearchViewController::search_model() { | 479 chrome::search::SearchModel* SearchViewController::search_model() { |
| 459 return tab_ ? tab_->search_tab_helper()->model() : NULL; | 480 return tab_contents_ ? tab_contents_->search_tab_helper()->model() : NULL; |
| 460 } | 481 } |
| 482 |
| 483 content::WebContents* SearchViewController::web_contents() { |
| 484 return tab_contents_ ? tab_contents_->web_contents() : NULL; |
| 485 } |
| OLD | NEW |