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/thread_proxy.h" | 5 #include "cc/trees/thread_proxy.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 #include <string> | 8 #include <string> |
9 | 9 |
10 #include "base/auto_reset.h" | 10 #include "base/auto_reset.h" |
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
90 ThreadProxy::MainThreadOnly::~MainThreadOnly() {} | 90 ThreadProxy::MainThreadOnly::~MainThreadOnly() {} |
91 | 91 |
92 ThreadProxy::MainThreadOrBlockedMainThread::MainThreadOrBlockedMainThread( | 92 ThreadProxy::MainThreadOrBlockedMainThread::MainThreadOrBlockedMainThread( |
93 LayerTreeHost* host) | 93 LayerTreeHost* host) |
94 : layer_tree_host(host), | 94 : layer_tree_host(host), |
95 commit_waits_for_activation(false), | 95 commit_waits_for_activation(false), |
96 main_thread_inside_commit(false) {} | 96 main_thread_inside_commit(false) {} |
97 | 97 |
98 ThreadProxy::MainThreadOrBlockedMainThread::~MainThreadOrBlockedMainThread() {} | 98 ThreadProxy::MainThreadOrBlockedMainThread::~MainThreadOrBlockedMainThread() {} |
99 | 99 |
100 PrioritizedResourceManager* | |
101 ThreadProxy::MainThreadOrBlockedMainThread::contents_texture_manager() { | |
102 return layer_tree_host->contents_texture_manager(); | |
103 } | |
104 | |
105 ThreadProxy::CompositorThreadOnly::CompositorThreadOnly( | 100 ThreadProxy::CompositorThreadOnly::CompositorThreadOnly( |
106 ThreadProxy* proxy, | 101 ThreadProxy* proxy, |
107 int layer_tree_host_id, | 102 int layer_tree_host_id, |
108 RenderingStatsInstrumentation* rendering_stats_instrumentation, | 103 RenderingStatsInstrumentation* rendering_stats_instrumentation, |
109 scoped_ptr<BeginFrameSource> external_begin_frame_source) | 104 scoped_ptr<BeginFrameSource> external_begin_frame_source) |
110 : layer_tree_host_id(layer_tree_host_id), | 105 : layer_tree_host_id(layer_tree_host_id), |
111 contents_texture_manager(NULL), | |
112 commit_completion_event(NULL), | 106 commit_completion_event(NULL), |
113 completion_event_for_commit_held_on_tree_activation(NULL), | 107 completion_event_for_commit_held_on_tree_activation(NULL), |
114 next_frame_is_newly_committed_frame(false), | 108 next_frame_is_newly_committed_frame(false), |
115 inside_draw(false), | 109 inside_draw(false), |
116 input_throttled_until_commit(false), | 110 input_throttled_until_commit(false), |
117 smoothness_priority_expiration_notifier( | 111 smoothness_priority_expiration_notifier( |
118 proxy->ImplThreadTaskRunner(), | 112 proxy->ImplThreadTaskRunner(), |
119 base::Bind(&ThreadProxy::RenewTreePriority, base::Unretained(proxy)), | 113 base::Bind(&ThreadProxy::RenewTreePriority, base::Unretained(proxy)), |
120 base::TimeDelta::FromMilliseconds( | 114 base::TimeDelta::FromMilliseconds( |
121 kSmoothnessTakesPriorityExpirationDelay * 1000)), | 115 kSmoothnessTakesPriorityExpirationDelay * 1000)), |
(...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
205 void ThreadProxy::SetThrottleFrameProductionOnImplThread(bool throttle) { | 199 void ThreadProxy::SetThrottleFrameProductionOnImplThread(bool throttle) { |
206 TRACE_EVENT1("cc", "ThreadProxy::SetThrottleFrameProductionOnImplThread", | 200 TRACE_EVENT1("cc", "ThreadProxy::SetThrottleFrameProductionOnImplThread", |
207 "throttle", throttle); | 201 "throttle", throttle); |
208 impl().scheduler->SetThrottleFrameProduction(throttle); | 202 impl().scheduler->SetThrottleFrameProduction(throttle); |
209 } | 203 } |
210 | 204 |
211 void ThreadProxy::DidLoseOutputSurface() { | 205 void ThreadProxy::DidLoseOutputSurface() { |
212 TRACE_EVENT0("cc", "ThreadProxy::DidLoseOutputSurface"); | 206 TRACE_EVENT0("cc", "ThreadProxy::DidLoseOutputSurface"); |
213 DCHECK(IsMainThread()); | 207 DCHECK(IsMainThread()); |
214 layer_tree_host()->DidLoseOutputSurface(); | 208 layer_tree_host()->DidLoseOutputSurface(); |
215 | |
216 { | |
217 DebugScopedSetMainThreadBlocked main_thread_blocked(this); | |
218 | |
219 // Return lost resources to their owners immediately. | |
220 BlockingTaskRunner::CapturePostTasks blocked( | |
221 blocking_main_thread_task_runner()); | |
222 | |
223 CompletionEvent completion; | |
224 Proxy::ImplThreadTaskRunner()->PostTask( | |
225 FROM_HERE, | |
226 base::Bind(&ThreadProxy::DeleteContentsTexturesOnImplThread, | |
227 impl_thread_weak_ptr_, | |
228 &completion)); | |
229 completion.Wait(); | |
230 } | |
231 } | 209 } |
232 | 210 |
233 void ThreadProxy::RequestNewOutputSurface() { | 211 void ThreadProxy::RequestNewOutputSurface() { |
234 DCHECK(IsMainThread()); | 212 DCHECK(IsMainThread()); |
235 layer_tree_host()->RequestNewOutputSurface(); | 213 layer_tree_host()->RequestNewOutputSurface(); |
236 } | 214 } |
237 | 215 |
238 void ThreadProxy::SetOutputSurface(scoped_ptr<OutputSurface> output_surface) { | 216 void ThreadProxy::SetOutputSurface(scoped_ptr<OutputSurface> output_surface) { |
239 Proxy::ImplThreadTaskRunner()->PostTask( | 217 Proxy::ImplThreadTaskRunner()->PostTask( |
240 FROM_HERE, | 218 FROM_HERE, |
(...skipping 173 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
414 TRACE_EVENT0("cc", | 392 TRACE_EVENT0("cc", |
415 "ThreadProxy::PostAnimationEventsToMainThreadOnImplThread"); | 393 "ThreadProxy::PostAnimationEventsToMainThreadOnImplThread"); |
416 DCHECK(IsImplThread()); | 394 DCHECK(IsImplThread()); |
417 Proxy::MainThreadTaskRunner()->PostTask( | 395 Proxy::MainThreadTaskRunner()->PostTask( |
418 FROM_HERE, | 396 FROM_HERE, |
419 base::Bind(&ThreadProxy::SetAnimationEvents, | 397 base::Bind(&ThreadProxy::SetAnimationEvents, |
420 main_thread_weak_ptr_, | 398 main_thread_weak_ptr_, |
421 base::Passed(&events))); | 399 base::Passed(&events))); |
422 } | 400 } |
423 | 401 |
424 bool ThreadProxy::ReduceContentsTextureMemoryOnImplThread(size_t limit_bytes, | |
425 int priority_cutoff) { | |
426 DCHECK(IsImplThread()); | |
427 | |
428 if (!impl().contents_texture_manager) | |
429 return false; | |
430 if (!impl().layer_tree_host_impl->resource_provider()) | |
431 return false; | |
432 | |
433 bool reduce_result = | |
434 impl().contents_texture_manager->ReduceMemoryOnImplThread( | |
435 limit_bytes, | |
436 priority_cutoff, | |
437 impl().layer_tree_host_impl->resource_provider()); | |
438 if (!reduce_result) | |
439 return false; | |
440 | |
441 // The texture upload queue may reference textures that were just purged, | |
442 // clear them from the queue. | |
443 if (impl().current_resource_update_controller) { | |
444 impl() | |
445 .current_resource_update_controller->DiscardUploadsToEvictedResources(); | |
446 } | |
447 return true; | |
448 } | |
449 | |
450 bool ThreadProxy::IsInsideDraw() { return impl().inside_draw; } | 402 bool ThreadProxy::IsInsideDraw() { return impl().inside_draw; } |
451 | 403 |
452 void ThreadProxy::SetNeedsRedraw(const gfx::Rect& damage_rect) { | 404 void ThreadProxy::SetNeedsRedraw(const gfx::Rect& damage_rect) { |
453 TRACE_EVENT0("cc", "ThreadProxy::SetNeedsRedraw"); | 405 TRACE_EVENT0("cc", "ThreadProxy::SetNeedsRedraw"); |
454 DCHECK(IsMainThread()); | 406 DCHECK(IsMainThread()); |
455 Proxy::ImplThreadTaskRunner()->PostTask( | 407 Proxy::ImplThreadTaskRunner()->PostTask( |
456 FROM_HERE, | 408 FROM_HERE, |
457 base::Bind(&ThreadProxy::SetNeedsRedrawRectOnImplThread, | 409 base::Bind(&ThreadProxy::SetNeedsRedrawRectOnImplThread, |
458 impl_thread_weak_ptr_, | 410 impl_thread_weak_ptr_, |
459 damage_rect)); | 411 damage_rect)); |
(...skipping 329 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
789 | 741 |
790 layer_tree_host()->ApplyScrollAndScale( | 742 layer_tree_host()->ApplyScrollAndScale( |
791 begin_main_frame_state->scroll_info.get()); | 743 begin_main_frame_state->scroll_info.get()); |
792 | 744 |
793 layer_tree_host()->WillBeginMainFrame(); | 745 layer_tree_host()->WillBeginMainFrame(); |
794 | 746 |
795 layer_tree_host()->BeginMainFrame(begin_main_frame_state->begin_frame_args); | 747 layer_tree_host()->BeginMainFrame(begin_main_frame_state->begin_frame_args); |
796 layer_tree_host()->AnimateLayers( | 748 layer_tree_host()->AnimateLayers( |
797 begin_main_frame_state->begin_frame_args.frame_time); | 749 begin_main_frame_state->begin_frame_args.frame_time); |
798 | 750 |
799 // Unlink any backings that the impl thread has evicted, so that we know to | |
800 // re-paint them in UpdateLayers. | |
801 if (blocked_main().contents_texture_manager()) { | |
802 blocked_main().contents_texture_manager()->UnlinkAndClearEvictedBackings(); | |
803 | |
804 blocked_main().contents_texture_manager()->SetMaxMemoryLimitBytes( | |
805 begin_main_frame_state->memory_allocation_limit_bytes); | |
806 blocked_main().contents_texture_manager()->SetExternalPriorityCutoff( | |
807 begin_main_frame_state->memory_allocation_priority_cutoff); | |
808 } | |
809 | |
810 // Recreate all UI resources if there were evicted UI resources when the impl | 751 // Recreate all UI resources if there were evicted UI resources when the impl |
811 // thread initiated the commit. | 752 // thread initiated the commit. |
812 if (begin_main_frame_state->evicted_ui_resources) | 753 if (begin_main_frame_state->evicted_ui_resources) |
813 layer_tree_host()->RecreateUIResources(); | 754 layer_tree_host()->RecreateUIResources(); |
814 | 755 |
815 layer_tree_host()->Layout(); | 756 layer_tree_host()->Layout(); |
816 TRACE_EVENT_SYNTHETIC_DELAY_END("cc.BeginMainFrame"); | 757 TRACE_EVENT_SYNTHETIC_DELAY_END("cc.BeginMainFrame"); |
817 | 758 |
818 // Clear the commit flag after updating animations and layout here --- objects | 759 // Clear the commit flag after updating animations and layout here --- objects |
819 // that only layout when painted will trigger another SetNeedsCommit inside | 760 // that only layout when painted will trigger another SetNeedsCommit inside |
(...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
909 completion->Signal(); | 850 completion->Signal(); |
910 return; | 851 return; |
911 } | 852 } |
912 | 853 |
913 // Ideally, we should inform to impl thread when BeginMainFrame is started. | 854 // Ideally, we should inform to impl thread when BeginMainFrame is started. |
914 // But, we can avoid a PostTask in here. | 855 // But, we can avoid a PostTask in here. |
915 impl().scheduler->NotifyBeginMainFrameStarted(); | 856 impl().scheduler->NotifyBeginMainFrameStarted(); |
916 | 857 |
917 scoped_ptr<ResourceUpdateQueue> queue(raw_queue); | 858 scoped_ptr<ResourceUpdateQueue> queue(raw_queue); |
918 | 859 |
919 if (impl().contents_texture_manager) { | |
920 DCHECK_EQ(impl().contents_texture_manager, | |
921 blocked_main().contents_texture_manager()); | |
922 } else { | |
923 // Cache this pointer that was created on the main thread side to avoid a | |
924 // data race between creating it and using it on the compositor thread. | |
925 impl().contents_texture_manager = blocked_main().contents_texture_manager(); | |
926 } | |
927 | |
928 if (impl().contents_texture_manager) { | |
929 if (impl().contents_texture_manager->LinkedEvictedBackingsExist()) { | |
930 // Clear any uploads we were making to textures linked to evicted | |
931 // resources | |
932 queue->ClearUploadsToEvictedResources(); | |
933 // Some textures in the layer tree are invalid. Kick off another commit | |
934 // to fill them again. | |
935 SetNeedsCommitOnImplThread(); | |
936 } | |
937 | |
938 impl().contents_texture_manager->PushTexturePrioritiesToBackings(); | |
939 } | |
940 | |
941 impl().commit_completion_event = completion; | 860 impl().commit_completion_event = completion; |
942 impl().current_resource_update_controller = ResourceUpdateController::Create( | 861 impl().current_resource_update_controller = ResourceUpdateController::Create( |
943 this, | 862 this, |
944 Proxy::ImplThreadTaskRunner(), | 863 Proxy::ImplThreadTaskRunner(), |
945 queue.Pass(), | 864 queue.Pass(), |
946 impl().layer_tree_host_impl->resource_provider()); | 865 impl().layer_tree_host_impl->resource_provider()); |
947 impl().current_resource_update_controller->PerformMoreUpdates( | 866 impl().current_resource_update_controller->PerformMoreUpdates( |
948 impl().scheduler->AnticipatedDrawTime()); | 867 impl().scheduler->AnticipatedDrawTime()); |
949 } | 868 } |
950 | 869 |
(...skipping 255 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1206 this, | 1125 this, |
1207 scheduler_settings, | 1126 scheduler_settings, |
1208 impl().layer_tree_host_id, | 1127 impl().layer_tree_host_id, |
1209 ImplThreadTaskRunner(), | 1128 ImplThreadTaskRunner(), |
1210 impl().external_begin_frame_source.Pass()); | 1129 impl().external_begin_frame_source.Pass()); |
1211 impl().scheduler->SetVisible(impl().layer_tree_host_impl->visible()); | 1130 impl().scheduler->SetVisible(impl().layer_tree_host_impl->visible()); |
1212 impl_thread_weak_ptr_ = impl().weak_factory.GetWeakPtr(); | 1131 impl_thread_weak_ptr_ = impl().weak_factory.GetWeakPtr(); |
1213 completion->Signal(); | 1132 completion->Signal(); |
1214 } | 1133 } |
1215 | 1134 |
1216 void ThreadProxy::DeleteContentsTexturesOnImplThread( | |
1217 CompletionEvent* completion) { | |
1218 TRACE_EVENT0("cc", "ThreadProxy::DeleteContentsTexturesOnImplThread"); | |
1219 DCHECK(IsImplThread()); | |
1220 DCHECK(IsMainThreadBlocked()); | |
1221 layer_tree_host()->DeleteContentsTexturesOnImplThread( | |
1222 impl().layer_tree_host_impl->resource_provider()); | |
1223 completion->Signal(); | |
1224 } | |
1225 | |
1226 void ThreadProxy::InitializeOutputSurfaceOnImplThread( | 1135 void ThreadProxy::InitializeOutputSurfaceOnImplThread( |
1227 scoped_ptr<OutputSurface> output_surface) { | 1136 scoped_ptr<OutputSurface> output_surface) { |
1228 TRACE_EVENT0("cc", "ThreadProxy::InitializeOutputSurfaceOnImplThread"); | 1137 TRACE_EVENT0("cc", "ThreadProxy::InitializeOutputSurfaceOnImplThread"); |
1229 DCHECK(IsImplThread()); | 1138 DCHECK(IsImplThread()); |
1230 | 1139 |
1231 LayerTreeHostImpl* host_impl = impl().layer_tree_host_impl.get(); | 1140 LayerTreeHostImpl* host_impl = impl().layer_tree_host_impl.get(); |
1232 bool success = host_impl->InitializeRenderer(output_surface.Pass()); | 1141 bool success = host_impl->InitializeRenderer(output_surface.Pass()); |
1233 RendererCapabilities capabilities; | 1142 RendererCapabilities capabilities; |
1234 if (success) { | 1143 if (success) { |
1235 capabilities = | 1144 capabilities = |
(...skipping 20 matching lines...) Expand all Loading... |
1256 if (context_provider) | 1165 if (context_provider) |
1257 context_provider->ContextGL()->Finish(); | 1166 context_provider->ContextGL()->Finish(); |
1258 } | 1167 } |
1259 completion->Signal(); | 1168 completion->Signal(); |
1260 } | 1169 } |
1261 | 1170 |
1262 void ThreadProxy::LayerTreeHostClosedOnImplThread(CompletionEvent* completion) { | 1171 void ThreadProxy::LayerTreeHostClosedOnImplThread(CompletionEvent* completion) { |
1263 TRACE_EVENT0("cc", "ThreadProxy::LayerTreeHostClosedOnImplThread"); | 1172 TRACE_EVENT0("cc", "ThreadProxy::LayerTreeHostClosedOnImplThread"); |
1264 DCHECK(IsImplThread()); | 1173 DCHECK(IsImplThread()); |
1265 DCHECK(IsMainThreadBlocked()); | 1174 DCHECK(IsMainThreadBlocked()); |
1266 layer_tree_host()->DeleteContentsTexturesOnImplThread( | |
1267 impl().layer_tree_host_impl->resource_provider()); | |
1268 impl().current_resource_update_controller = nullptr; | 1175 impl().current_resource_update_controller = nullptr; |
1269 impl().scheduler = nullptr; | 1176 impl().scheduler = nullptr; |
1270 impl().layer_tree_host_impl = nullptr; | 1177 impl().layer_tree_host_impl = nullptr; |
1271 impl().weak_factory.InvalidateWeakPtrs(); | 1178 impl().weak_factory.InvalidateWeakPtrs(); |
1272 // We need to explicitly shutdown the notifier to destroy any weakptrs it is | 1179 // We need to explicitly shutdown the notifier to destroy any weakptrs it is |
1273 // holding while still on the compositor thread. This also ensures any | 1180 // holding while still on the compositor thread. This also ensures any |
1274 // callbacks holding a ThreadProxy pointer are cancelled. | 1181 // callbacks holding a ThreadProxy pointer are cancelled. |
1275 impl().smoothness_priority_expiration_notifier.Shutdown(); | 1182 impl().smoothness_priority_expiration_notifier.Shutdown(); |
1276 impl().contents_texture_manager = NULL; | |
1277 completion->Signal(); | 1183 completion->Signal(); |
1278 } | 1184 } |
1279 | 1185 |
1280 size_t ThreadProxy::MaxPartialTextureUpdates() const { | 1186 size_t ThreadProxy::MaxPartialTextureUpdates() const { |
1281 return ResourceUpdateController::MaxPartialTextureUpdates(); | 1187 return ResourceUpdateController::MaxPartialTextureUpdates(); |
1282 } | 1188 } |
1283 | 1189 |
1284 ThreadProxy::BeginMainFrameAndCommitState::BeginMainFrameAndCommitState() | 1190 ThreadProxy::BeginMainFrameAndCommitState::BeginMainFrameAndCommitState() |
1285 : memory_allocation_limit_bytes(0), | 1191 : memory_allocation_limit_bytes(0), |
1286 memory_allocation_priority_cutoff(0), | 1192 memory_allocation_priority_cutoff(0), |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1332 if (smoothness_takes_priority) | 1238 if (smoothness_takes_priority) |
1333 impl().smoothness_priority_expiration_notifier.Schedule(); | 1239 impl().smoothness_priority_expiration_notifier.Schedule(); |
1334 | 1240 |
1335 // We use the same priority for both trees by default. | 1241 // We use the same priority for both trees by default. |
1336 TreePriority priority = SAME_PRIORITY_FOR_BOTH_TREES; | 1242 TreePriority priority = SAME_PRIORITY_FOR_BOTH_TREES; |
1337 | 1243 |
1338 // Smoothness takes priority if we have an expiration for it scheduled. | 1244 // Smoothness takes priority if we have an expiration for it scheduled. |
1339 if (impl().smoothness_priority_expiration_notifier.HasPendingNotification()) | 1245 if (impl().smoothness_priority_expiration_notifier.HasPendingNotification()) |
1340 priority = SMOOTHNESS_TAKES_PRIORITY; | 1246 priority = SMOOTHNESS_TAKES_PRIORITY; |
1341 | 1247 |
1342 // New content always takes priority when the active tree has | 1248 // New content always takes priority when there is an invalid viewport size or |
1343 // evicted resources or there is an invalid viewport size. | 1249 // ui resources have been evicted. |
1344 if (impl().layer_tree_host_impl->active_tree()->ContentsTexturesPurged() || | 1250 if (impl().layer_tree_host_impl->active_tree()->ViewportSizeInvalid() || |
1345 impl().layer_tree_host_impl->active_tree()->ViewportSizeInvalid() || | |
1346 impl().layer_tree_host_impl->EvictedUIResourcesExist() || | 1251 impl().layer_tree_host_impl->EvictedUIResourcesExist() || |
1347 impl().input_throttled_until_commit) { | 1252 impl().input_throttled_until_commit) { |
1348 // Once we enter NEW_CONTENTS_TAKES_PRIORITY mode, visible tiles on active | 1253 // Once we enter NEW_CONTENTS_TAKES_PRIORITY mode, visible tiles on active |
1349 // tree might be freed. We need to set RequiresHighResToDraw to ensure that | 1254 // tree might be freed. We need to set RequiresHighResToDraw to ensure that |
1350 // high res tiles will be required to activate pending tree. | 1255 // high res tiles will be required to activate pending tree. |
1351 impl().layer_tree_host_impl->SetRequiresHighResToDraw(); | 1256 impl().layer_tree_host_impl->SetRequiresHighResToDraw(); |
1352 priority = NEW_CONTENT_TAKES_PRIORITY; | 1257 priority = NEW_CONTENT_TAKES_PRIORITY; |
1353 } | 1258 } |
1354 | 1259 |
1355 impl().layer_tree_host_impl->SetTreePriority(priority); | 1260 impl().layer_tree_host_impl->SetTreePriority(priority); |
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1425 | 1330 |
1426 void ThreadProxy::PostFrameTimingEvents( | 1331 void ThreadProxy::PostFrameTimingEvents( |
1427 scoped_ptr<FrameTimingTracker::CompositeTimingSet> composite_events, | 1332 scoped_ptr<FrameTimingTracker::CompositeTimingSet> composite_events, |
1428 scoped_ptr<FrameTimingTracker::MainFrameTimingSet> main_frame_events) { | 1333 scoped_ptr<FrameTimingTracker::MainFrameTimingSet> main_frame_events) { |
1429 DCHECK(IsMainThread()); | 1334 DCHECK(IsMainThread()); |
1430 layer_tree_host()->RecordFrameTimingEvents(composite_events.Pass(), | 1335 layer_tree_host()->RecordFrameTimingEvents(composite_events.Pass(), |
1431 main_frame_events.Pass()); | 1336 main_frame_events.Pass()); |
1432 } | 1337 } |
1433 | 1338 |
1434 } // namespace cc | 1339 } // namespace cc |
OLD | NEW |