| OLD | NEW |
| 1 // Copyright 2011 The Chromium Authors. All rights reserved. | 1 // Copyright 2011 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 "cc/trees/single_thread_proxy.h" | 5 #include "cc/trees/single_thread_proxy.h" |
| 6 | 6 |
| 7 #include "base/auto_reset.h" | 7 #include "base/auto_reset.h" |
| 8 #include "base/debug/trace_event.h" | 8 #include "base/debug/trace_event.h" |
| 9 #include "cc/debug/benchmark_instrumentation.h" | 9 #include "cc/debug/benchmark_instrumentation.h" |
| 10 #include "cc/output/context_provider.h" | 10 #include "cc/output/context_provider.h" |
| (...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 94 } | 94 } |
| 95 } | 95 } |
| 96 | 96 |
| 97 void SingleThreadProxy::SetVisible(bool visible) { | 97 void SingleThreadProxy::SetVisible(bool visible) { |
| 98 TRACE_EVENT0("cc", "SingleThreadProxy::SetVisible"); | 98 TRACE_EVENT0("cc", "SingleThreadProxy::SetVisible"); |
| 99 DebugScopedSetImplThread impl(this); | 99 DebugScopedSetImplThread impl(this); |
| 100 layer_tree_host_impl_->SetVisible(visible); | 100 layer_tree_host_impl_->SetVisible(visible); |
| 101 if (scheduler_on_impl_thread_) | 101 if (scheduler_on_impl_thread_) |
| 102 scheduler_on_impl_thread_->SetVisible(layer_tree_host_impl_->visible()); | 102 scheduler_on_impl_thread_->SetVisible(layer_tree_host_impl_->visible()); |
| 103 // Changing visibility could change ShouldComposite(). | 103 // Changing visibility could change ShouldComposite(). |
| 104 UpdateBackgroundAnimateTicking(); | |
| 105 } | 104 } |
| 106 | 105 |
| 107 void SingleThreadProxy::RequestNewOutputSurface() { | 106 void SingleThreadProxy::RequestNewOutputSurface() { |
| 108 DCHECK(Proxy::IsMainThread()); | 107 DCHECK(Proxy::IsMainThread()); |
| 109 DCHECK(layer_tree_host_->output_surface_lost()); | 108 DCHECK(layer_tree_host_->output_surface_lost()); |
| 110 output_surface_creation_callback_.Cancel(); | 109 output_surface_creation_callback_.Cancel(); |
| 111 if (output_surface_creation_requested_) | 110 if (output_surface_creation_requested_) |
| 112 return; | 111 return; |
| 113 output_surface_creation_requested_ = true; | 112 output_surface_creation_requested_ = true; |
| 114 layer_tree_host_->RequestNewOutputSurface(); | 113 layer_tree_host_->RequestNewOutputSurface(); |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 154 client_->ScheduleAnimation(); | 153 client_->ScheduleAnimation(); |
| 155 SetNeedsCommit(); | 154 SetNeedsCommit(); |
| 156 } | 155 } |
| 157 | 156 |
| 158 void SingleThreadProxy::SetNeedsUpdateLayers() { | 157 void SingleThreadProxy::SetNeedsUpdateLayers() { |
| 159 TRACE_EVENT0("cc", "SingleThreadProxy::SetNeedsUpdateLayers"); | 158 TRACE_EVENT0("cc", "SingleThreadProxy::SetNeedsUpdateLayers"); |
| 160 DCHECK(Proxy::IsMainThread()); | 159 DCHECK(Proxy::IsMainThread()); |
| 161 SetNeedsCommit(); | 160 SetNeedsCommit(); |
| 162 } | 161 } |
| 163 | 162 |
| 163 void SingleThreadProxy::DoAnimate() { |
| 164 // Don't animate if there is no root layer. |
| 165 // TODO(mithro): Both Animate and UpdateAnimationState already have a |
| 166 // "!active_tree_->root_layer()" check? |
| 167 if (!layer_tree_host_impl_->active_tree()->root_layer()) { |
| 168 return; |
| 169 } |
| 170 |
| 171 layer_tree_host_impl_->Animate( |
| 172 layer_tree_host_impl_->CurrentBeginFrameArgs().frame_time); |
| 173 |
| 174 // If animations are not visible, update the animation state now as it |
| 175 // won't happen in DoComposite. |
| 176 if (!layer_tree_host_impl_->AnimationsAreVisible()) { |
| 177 layer_tree_host_impl_->UpdateAnimationState(true); |
| 178 } |
| 179 } |
| 180 |
| 164 void SingleThreadProxy::DoCommit() { | 181 void SingleThreadProxy::DoCommit() { |
| 165 TRACE_EVENT0("cc", "SingleThreadProxy::DoCommit"); | 182 TRACE_EVENT0("cc", "SingleThreadProxy::DoCommit"); |
| 166 DCHECK(Proxy::IsMainThread()); | 183 DCHECK(Proxy::IsMainThread()); |
| 167 | 184 |
| 168 commit_requested_ = false; | 185 commit_requested_ = false; |
| 169 layer_tree_host_->WillCommit(); | 186 layer_tree_host_->WillCommit(); |
| 170 | 187 |
| 171 // Commit immediately. | 188 // Commit immediately. |
| 172 { | 189 { |
| 173 DebugScopedSetMainThreadBlocked main_thread_blocked(this); | 190 DebugScopedSetMainThreadBlocked main_thread_blocked(this); |
| (...skipping 21 matching lines...) Expand all Loading... |
| 195 layer_tree_host_impl_->resource_provider()); | 212 layer_tree_host_impl_->resource_provider()); |
| 196 update_controller->Finalize(); | 213 update_controller->Finalize(); |
| 197 | 214 |
| 198 if (layer_tree_host_impl_->EvictedUIResourcesExist()) | 215 if (layer_tree_host_impl_->EvictedUIResourcesExist()) |
| 199 layer_tree_host_->RecreateUIResources(); | 216 layer_tree_host_->RecreateUIResources(); |
| 200 | 217 |
| 201 layer_tree_host_->FinishCommitOnImplThread(layer_tree_host_impl_.get()); | 218 layer_tree_host_->FinishCommitOnImplThread(layer_tree_host_impl_.get()); |
| 202 | 219 |
| 203 layer_tree_host_impl_->CommitComplete(); | 220 layer_tree_host_impl_->CommitComplete(); |
| 204 | 221 |
| 205 UpdateBackgroundAnimateTicking(); | |
| 206 | |
| 207 #if DCHECK_IS_ON | 222 #if DCHECK_IS_ON |
| 208 // In the single-threaded case, the scale and scroll deltas should never be | 223 // In the single-threaded case, the scale and scroll deltas should never be |
| 209 // touched on the impl layer tree. | 224 // touched on the impl layer tree. |
| 210 scoped_ptr<ScrollAndScaleSet> scroll_info = | 225 scoped_ptr<ScrollAndScaleSet> scroll_info = |
| 211 layer_tree_host_impl_->ProcessScrollDeltas(); | 226 layer_tree_host_impl_->ProcessScrollDeltas(); |
| 212 DCHECK(!scroll_info->scrolls.size()); | 227 DCHECK(!scroll_info->scrolls.size()); |
| 213 DCHECK_EQ(1.f, scroll_info->page_scale_delta); | 228 DCHECK_EQ(1.f, scroll_info->page_scale_delta); |
| 214 #endif | 229 #endif |
| 215 } | 230 } |
| 216 | 231 |
| (...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 315 scheduler_on_impl_thread_ = nullptr; | 330 scheduler_on_impl_thread_ = nullptr; |
| 316 layer_tree_host_impl_ = nullptr; | 331 layer_tree_host_impl_ = nullptr; |
| 317 } | 332 } |
| 318 layer_tree_host_ = NULL; | 333 layer_tree_host_ = NULL; |
| 319 } | 334 } |
| 320 | 335 |
| 321 void SingleThreadProxy::OnCanDrawStateChanged(bool can_draw) { | 336 void SingleThreadProxy::OnCanDrawStateChanged(bool can_draw) { |
| 322 TRACE_EVENT1( | 337 TRACE_EVENT1( |
| 323 "cc", "SingleThreadProxy::OnCanDrawStateChanged", "can_draw", can_draw); | 338 "cc", "SingleThreadProxy::OnCanDrawStateChanged", "can_draw", can_draw); |
| 324 DCHECK(Proxy::IsImplThread()); | 339 DCHECK(Proxy::IsImplThread()); |
| 325 UpdateBackgroundAnimateTicking(); | |
| 326 if (scheduler_on_impl_thread_) | 340 if (scheduler_on_impl_thread_) |
| 327 scheduler_on_impl_thread_->SetCanDraw(can_draw); | 341 scheduler_on_impl_thread_->SetCanDraw(can_draw); |
| 328 } | 342 } |
| 329 | 343 |
| 330 void SingleThreadProxy::NotifyReadyToActivate() { | 344 void SingleThreadProxy::NotifyReadyToActivate() { |
| 331 TRACE_EVENT0("cc", "SingleThreadProxy::NotifyReadyToActivate"); | 345 TRACE_EVENT0("cc", "SingleThreadProxy::NotifyReadyToActivate"); |
| 332 DebugScopedSetImplThread impl(this); | 346 DebugScopedSetImplThread impl(this); |
| 333 if (scheduler_on_impl_thread_) | 347 if (scheduler_on_impl_thread_) |
| 334 scheduler_on_impl_thread_->NotifyReadyToActivate(); | 348 scheduler_on_impl_thread_->NotifyReadyToActivate(); |
| 335 } | 349 } |
| 336 | 350 |
| 337 void SingleThreadProxy::SetNeedsRedrawOnImplThread() { | 351 void SingleThreadProxy::SetNeedsRedrawOnImplThread() { |
| 338 client_->ScheduleComposite(); | 352 client_->ScheduleComposite(); |
| 339 if (scheduler_on_impl_thread_) | 353 if (scheduler_on_impl_thread_) |
| 340 scheduler_on_impl_thread_->SetNeedsRedraw(); | 354 scheduler_on_impl_thread_->SetNeedsRedraw(); |
| 341 } | 355 } |
| 342 | 356 |
| 343 void SingleThreadProxy::SetNeedsAnimateOnImplThread() { | 357 void SingleThreadProxy::SetNeedsAnimateOnImplThread() { |
| 344 SetNeedsRedrawOnImplThread(); | 358 client_->ScheduleComposite(); |
| 359 if (scheduler_on_impl_thread_) |
| 360 scheduler_on_impl_thread_->SetNeedsAnimate(); |
| 345 } | 361 } |
| 346 | 362 |
| 347 void SingleThreadProxy::SetNeedsManageTilesOnImplThread() { | 363 void SingleThreadProxy::SetNeedsManageTilesOnImplThread() { |
| 348 TRACE_EVENT0("cc", "SingleThreadProxy::SetNeedsManageTilesOnImplThread"); | 364 TRACE_EVENT0("cc", "SingleThreadProxy::SetNeedsManageTilesOnImplThread"); |
| 349 if (scheduler_on_impl_thread_) | 365 if (scheduler_on_impl_thread_) |
| 350 scheduler_on_impl_thread_->SetNeedsManageTiles(); | 366 scheduler_on_impl_thread_->SetNeedsManageTiles(); |
| 351 } | 367 } |
| 352 | 368 |
| 353 void SingleThreadProxy::SetNeedsRedrawRectOnImplThread( | 369 void SingleThreadProxy::SetNeedsRedrawRectOnImplThread( |
| 354 const gfx::Rect& damage_rect) { | 370 const gfx::Rect& damage_rect) { |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 407 // Since activation could cause tasks to run, post CommitComplete | 423 // Since activation could cause tasks to run, post CommitComplete |
| 408 // separately so that it runs after these tasks. This is the loose | 424 // separately so that it runs after these tasks. This is the loose |
| 409 // equivalent of blocking commit until activation and also running | 425 // equivalent of blocking commit until activation and also running |
| 410 // all tasks posted during commit/activation before CommitComplete. | 426 // all tasks posted during commit/activation before CommitComplete. |
| 411 MainThreadTaskRunner()->PostTask( | 427 MainThreadTaskRunner()->PostTask( |
| 412 FROM_HERE, | 428 FROM_HERE, |
| 413 base::Bind(&SingleThreadProxy::CommitComplete, | 429 base::Bind(&SingleThreadProxy::CommitComplete, |
| 414 weak_factory_.GetWeakPtr())); | 430 weak_factory_.GetWeakPtr())); |
| 415 } | 431 } |
| 416 | 432 |
| 417 UpdateBackgroundAnimateTicking(); | |
| 418 timing_history_.DidActivateSyncTree(); | 433 timing_history_.DidActivateSyncTree(); |
| 419 } | 434 } |
| 420 | 435 |
| 421 void SingleThreadProxy::DidManageTiles() { | 436 void SingleThreadProxy::DidManageTiles() { |
| 422 DCHECK(layer_tree_host_impl_->settings().impl_side_painting); | 437 DCHECK(layer_tree_host_impl_->settings().impl_side_painting); |
| 423 DCHECK(Proxy::IsImplThread()); | 438 DCHECK(Proxy::IsImplThread()); |
| 424 if (scheduler_on_impl_thread_) | 439 if (scheduler_on_impl_thread_) |
| 425 scheduler_on_impl_thread_->DidManageTiles(); | 440 scheduler_on_impl_thread_->DidManageTiles(); |
| 426 } | 441 } |
| 427 | 442 |
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 485 | 500 |
| 486 { | 501 { |
| 487 DebugScopedSetImplThread impl(const_cast<SingleThreadProxy*>(this)); | 502 DebugScopedSetImplThread impl(const_cast<SingleThreadProxy*>(this)); |
| 488 if (layer_tree_host_impl_->settings().impl_side_painting) { | 503 if (layer_tree_host_impl_->settings().impl_side_painting) { |
| 489 layer_tree_host_impl_->ActivateSyncTree(); | 504 layer_tree_host_impl_->ActivateSyncTree(); |
| 490 layer_tree_host_impl_->active_tree()->UpdateDrawProperties(); | 505 layer_tree_host_impl_->active_tree()->UpdateDrawProperties(); |
| 491 layer_tree_host_impl_->ManageTiles(); | 506 layer_tree_host_impl_->ManageTiles(); |
| 492 layer_tree_host_impl_->SynchronouslyInitializeAllTiles(); | 507 layer_tree_host_impl_->SynchronouslyInitializeAllTiles(); |
| 493 } | 508 } |
| 494 | 509 |
| 510 DoAnimate(); |
| 511 |
| 495 LayerTreeHostImpl::FrameData frame; | 512 LayerTreeHostImpl::FrameData frame; |
| 496 DoComposite(frame_begin_time, &frame); | 513 DoComposite(frame_begin_time, &frame); |
| 497 | 514 |
| 498 // DoComposite could abort, but because this is a synchronous composite | 515 // DoComposite could abort, but because this is a synchronous composite |
| 499 // another draw will never be scheduled, so break remaining promises. | 516 // another draw will never be scheduled, so break remaining promises. |
| 500 layer_tree_host_impl_->active_tree()->BreakSwapPromises( | 517 layer_tree_host_impl_->active_tree()->BreakSwapPromises( |
| 501 SwapPromise::SWAP_FAILS); | 518 SwapPromise::SWAP_FAILS); |
| 502 } | 519 } |
| 503 } | 520 } |
| 504 | 521 |
| (...skipping 21 matching lines...) Expand all Loading... |
| 526 bool SingleThreadProxy::SupportsImplScrolling() const { | 543 bool SingleThreadProxy::SupportsImplScrolling() const { |
| 527 return false; | 544 return false; |
| 528 } | 545 } |
| 529 | 546 |
| 530 bool SingleThreadProxy::ShouldComposite() const { | 547 bool SingleThreadProxy::ShouldComposite() const { |
| 531 DCHECK(Proxy::IsImplThread()); | 548 DCHECK(Proxy::IsImplThread()); |
| 532 return layer_tree_host_impl_->visible() && | 549 return layer_tree_host_impl_->visible() && |
| 533 layer_tree_host_impl_->CanDraw(); | 550 layer_tree_host_impl_->CanDraw(); |
| 534 } | 551 } |
| 535 | 552 |
| 536 void SingleThreadProxy::UpdateBackgroundAnimateTicking() { | |
| 537 DCHECK(Proxy::IsImplThread()); | |
| 538 layer_tree_host_impl_->UpdateBackgroundAnimateTicking( | |
| 539 !ShouldComposite() && layer_tree_host_impl_->active_tree()->root_layer()); | |
| 540 } | |
| 541 | |
| 542 void SingleThreadProxy::ScheduleRequestNewOutputSurface() { | 553 void SingleThreadProxy::ScheduleRequestNewOutputSurface() { |
| 543 if (output_surface_creation_callback_.IsCancelled() && | 554 if (output_surface_creation_callback_.IsCancelled() && |
| 544 !output_surface_creation_requested_) { | 555 !output_surface_creation_requested_) { |
| 545 output_surface_creation_callback_.Reset( | 556 output_surface_creation_callback_.Reset( |
| 546 base::Bind(&SingleThreadProxy::RequestNewOutputSurface, | 557 base::Bind(&SingleThreadProxy::RequestNewOutputSurface, |
| 547 weak_factory_.GetWeakPtr())); | 558 weak_factory_.GetWeakPtr())); |
| 548 MainThreadTaskRunner()->PostTask( | 559 MainThreadTaskRunner()->PostTask( |
| 549 FROM_HERE, output_surface_creation_callback_.callback()); | 560 FROM_HERE, output_surface_creation_callback_.callback()); |
| 550 } | 561 } |
| 551 } | 562 } |
| 552 | 563 |
| 553 DrawResult SingleThreadProxy::DoComposite(base::TimeTicks frame_begin_time, | 564 DrawResult SingleThreadProxy::DoComposite(base::TimeTicks frame_begin_time, |
| 554 LayerTreeHostImpl::FrameData* frame) { | 565 LayerTreeHostImpl::FrameData* frame) { |
| 555 TRACE_EVENT0("cc", "SingleThreadProxy::DoComposite"); | 566 TRACE_EVENT0("cc", "SingleThreadProxy::DoComposite"); |
| 556 DCHECK(!layer_tree_host_->output_surface_lost()); | 567 DCHECK(!layer_tree_host_->output_surface_lost()); |
| 557 | 568 |
| 558 DrawResult draw_result; | 569 DrawResult draw_result; |
| 559 bool draw_frame; | 570 bool draw_frame; |
| 560 { | 571 { |
| 561 DebugScopedSetImplThread impl(this); | 572 DebugScopedSetImplThread impl(this); |
| 562 base::AutoReset<bool> mark_inside(&inside_draw_, true); | 573 base::AutoReset<bool> mark_inside(&inside_draw_, true); |
| 563 | 574 |
| 564 // We guard PrepareToDraw() with CanDraw() because it always returns a valid | 575 // We guard PrepareToDraw() with CanDraw() because it always returns a valid |
| 565 // frame, so can only be used when such a frame is possible. Since | 576 // frame, so can only be used when such a frame is possible. Since |
| 566 // DrawLayers() depends on the result of PrepareToDraw(), it is guarded on | 577 // DrawLayers() depends on the result of PrepareToDraw(), it is guarded on |
| 567 // CanDraw() as well. | 578 // CanDraw() as well. |
| 568 if (!ShouldComposite()) { | 579 if (!ShouldComposite()) { |
| 569 UpdateBackgroundAnimateTicking(); | |
| 570 return DRAW_ABORTED_CANT_DRAW; | 580 return DRAW_ABORTED_CANT_DRAW; |
| 571 } | 581 } |
| 572 | 582 |
| 573 timing_history_.DidStartDrawing(); | 583 timing_history_.DidStartDrawing(); |
| 574 | 584 |
| 575 layer_tree_host_impl_->Animate( | |
| 576 layer_tree_host_impl_->CurrentBeginFrameArgs().frame_time); | |
| 577 UpdateBackgroundAnimateTicking(); | |
| 578 | |
| 579 draw_result = layer_tree_host_impl_->PrepareToDraw(frame); | 585 draw_result = layer_tree_host_impl_->PrepareToDraw(frame); |
| 580 draw_frame = draw_result == DRAW_SUCCESS; | 586 draw_frame = draw_result == DRAW_SUCCESS; |
| 581 if (draw_frame) | 587 if (draw_frame) |
| 582 layer_tree_host_impl_->DrawLayers(frame, frame_begin_time); | 588 layer_tree_host_impl_->DrawLayers(frame, frame_begin_time); |
| 583 layer_tree_host_impl_->DidDrawAllLayers(*frame); | 589 layer_tree_host_impl_->DidDrawAllLayers(*frame); |
| 584 | 590 |
| 585 bool start_ready_animations = draw_frame; | 591 bool start_ready_animations = draw_frame; |
| 586 layer_tree_host_impl_->UpdateAnimationState(start_ready_animations); | 592 layer_tree_host_impl_->UpdateAnimationState(start_ready_animations); |
| 587 layer_tree_host_impl_->ResetCurrentBeginFrameArgsForNextFrame(); | 593 layer_tree_host_impl_->ResetCurrentBeginFrameArgsForNextFrame(); |
| 588 | 594 |
| (...skipping 140 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 729 return INVALID_RESULT; | 735 return INVALID_RESULT; |
| 730 } | 736 } |
| 731 | 737 |
| 732 void SingleThreadProxy::ScheduledActionCommit() { | 738 void SingleThreadProxy::ScheduledActionCommit() { |
| 733 DebugScopedSetMainThread main(this); | 739 DebugScopedSetMainThread main(this); |
| 734 DoCommit(); | 740 DoCommit(); |
| 735 } | 741 } |
| 736 | 742 |
| 737 void SingleThreadProxy::ScheduledActionAnimate() { | 743 void SingleThreadProxy::ScheduledActionAnimate() { |
| 738 TRACE_EVENT0("cc", "ScheduledActionAnimate"); | 744 TRACE_EVENT0("cc", "ScheduledActionAnimate"); |
| 739 layer_tree_host_impl_->Animate( | 745 DebugScopedSetImplThread impl(this); |
| 740 layer_tree_host_impl_->CurrentBeginFrameArgs().frame_time); | 746 DoAnimate(); |
| 741 } | 747 } |
| 742 | 748 |
| 743 void SingleThreadProxy::ScheduledActionUpdateVisibleTiles() { | 749 void SingleThreadProxy::ScheduledActionUpdateVisibleTiles() { |
| 744 DebugScopedSetImplThread impl(this); | 750 DebugScopedSetImplThread impl(this); |
| 745 layer_tree_host_impl_->UpdateVisibleTiles(); | 751 layer_tree_host_impl_->UpdateVisibleTiles(); |
| 746 } | 752 } |
| 747 | 753 |
| 748 void SingleThreadProxy::ScheduledActionActivateSyncTree() { | 754 void SingleThreadProxy::ScheduledActionActivateSyncTree() { |
| 749 DebugScopedSetImplThread impl(this); | 755 DebugScopedSetImplThread impl(this); |
| 750 layer_tree_host_impl_->ActivateSyncTree(); | 756 layer_tree_host_impl_->ActivateSyncTree(); |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 784 | 790 |
| 785 base::TimeDelta SingleThreadProxy::CommitToActivateDurationEstimate() { | 791 base::TimeDelta SingleThreadProxy::CommitToActivateDurationEstimate() { |
| 786 return timing_history_.CommitToActivateDurationEstimate(); | 792 return timing_history_.CommitToActivateDurationEstimate(); |
| 787 } | 793 } |
| 788 | 794 |
| 789 void SingleThreadProxy::DidBeginImplFrameDeadline() { | 795 void SingleThreadProxy::DidBeginImplFrameDeadline() { |
| 790 layer_tree_host_impl_->ResetCurrentBeginFrameArgsForNextFrame(); | 796 layer_tree_host_impl_->ResetCurrentBeginFrameArgsForNextFrame(); |
| 791 } | 797 } |
| 792 | 798 |
| 793 } // namespace cc | 799 } // namespace cc |
| OLD | NEW |