| 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/scheduler/scheduler_state_machine.h" | 5 #include "cc/scheduler/scheduler_state_machine.h" |
| 6 | 6 |
| 7 #include "base/format_macros.h" | 7 #include "base/format_macros.h" |
| 8 #include "base/logging.h" | 8 #include "base/logging.h" |
| 9 #include "base/strings/stringprintf.h" | 9 #include "base/strings/stringprintf.h" |
| 10 #include "base/trace_event/trace_event.h" | 10 #include "base/trace_event/trace_event.h" |
| 11 #include "base/trace_event/trace_event_argument.h" | 11 #include "base/trace_event/trace_event_argument.h" |
| 12 #include "base/values.h" | 12 #include "base/values.h" |
| 13 | 13 |
| 14 namespace cc { | 14 namespace cc { |
| 15 | 15 |
| 16 SchedulerStateMachine::SchedulerStateMachine(const SchedulerSettings& settings) | 16 SchedulerStateMachine::SchedulerStateMachine(const SchedulerSettings& settings) |
| 17 : settings_(settings), | 17 : settings_(settings), |
| 18 output_surface_state_(OUTPUT_SURFACE_LOST), | 18 output_surface_state_(OUTPUT_SURFACE_NONE), |
| 19 begin_impl_frame_state_(BEGIN_IMPL_FRAME_STATE_IDLE), | 19 begin_impl_frame_state_(BEGIN_IMPL_FRAME_STATE_IDLE), |
| 20 begin_main_frame_state_(BEGIN_MAIN_FRAME_STATE_IDLE), | 20 begin_main_frame_state_(BEGIN_MAIN_FRAME_STATE_IDLE), |
| 21 forced_redraw_state_(FORCED_REDRAW_STATE_IDLE), | 21 forced_redraw_state_(FORCED_REDRAW_STATE_IDLE), |
| 22 commit_count_(0), | 22 commit_count_(0), |
| 23 current_frame_number_(0), | 23 current_frame_number_(0), |
| 24 last_frame_number_animate_performed_(-1), | 24 last_frame_number_animate_performed_(-1), |
| 25 last_frame_number_swap_performed_(-1), | 25 last_frame_number_swap_performed_(-1), |
| 26 last_frame_number_swap_requested_(-1), | 26 last_frame_number_swap_requested_(-1), |
| 27 last_frame_number_begin_main_frame_sent_(-1), | 27 last_frame_number_begin_main_frame_sent_(-1), |
| 28 last_frame_number_invalidate_output_surface_performed_(-1), | 28 last_frame_number_invalidate_output_surface_performed_(-1), |
| 29 animate_funnel_(false), | 29 animate_funnel_(false), |
| 30 request_swap_funnel_(false), | 30 request_swap_funnel_(false), |
| 31 send_begin_main_frame_funnel_(true), | 31 send_begin_main_frame_funnel_(true), |
| 32 invalidate_output_surface_funnel_(false), | 32 invalidate_output_surface_funnel_(false), |
| 33 prepare_tiles_funnel_(0), | 33 prepare_tiles_funnel_(0), |
| 34 consecutive_checkerboard_animations_(0), | 34 consecutive_checkerboard_animations_(0), |
| 35 max_pending_swaps_(1), | 35 max_pending_swaps_(1), |
| 36 pending_swaps_(0), | 36 pending_swaps_(0), |
| 37 swaps_with_current_output_surface_(0), | 37 swaps_with_current_output_surface_(0), |
| 38 needs_redraw_(false), | 38 needs_redraw_(false), |
| 39 needs_animate_(false), | 39 needs_animate_(false), |
| 40 needs_prepare_tiles_(false), | 40 needs_prepare_tiles_(false), |
| 41 needs_begin_main_frame_(false), | 41 needs_begin_main_frame_(false), |
| 42 visible_(false), | 42 visible_(false), |
| 43 can_start_(false), | |
| 44 can_draw_(false), | 43 can_draw_(false), |
| 45 has_pending_tree_(false), | 44 has_pending_tree_(false), |
| 46 pending_tree_is_ready_for_activation_(false), | 45 pending_tree_is_ready_for_activation_(false), |
| 47 active_tree_needs_first_draw_(false), | 46 active_tree_needs_first_draw_(false), |
| 48 did_create_and_initialize_first_output_surface_(false), | 47 did_create_and_initialize_first_output_surface_(false), |
| 49 impl_latency_takes_priority_(false), | 48 impl_latency_takes_priority_(false), |
| 50 main_thread_missed_last_deadline_(false), | 49 main_thread_missed_last_deadline_(false), |
| 51 skip_next_begin_main_frame_to_reduce_latency_(false), | 50 skip_next_begin_main_frame_to_reduce_latency_(false), |
| 52 children_need_begin_frames_(false), | 51 children_need_begin_frames_(false), |
| 53 defer_commits_(false), | 52 defer_commits_(false), |
| 54 video_needs_begin_frames_(false), | 53 video_needs_begin_frames_(false), |
| 55 last_commit_had_no_updates_(false), | 54 last_commit_had_no_updates_(false), |
| 56 wait_for_ready_to_draw_(false), | 55 wait_for_ready_to_draw_(false), |
| 57 did_request_swap_in_last_frame_(false), | 56 did_request_swap_in_last_frame_(false), |
| 58 did_perform_swap_in_last_draw_(false) {} | 57 did_perform_swap_in_last_draw_(false) {} |
| 59 | 58 |
| 60 const char* SchedulerStateMachine::OutputSurfaceStateToString( | 59 const char* SchedulerStateMachine::OutputSurfaceStateToString( |
| 61 OutputSurfaceState state) { | 60 OutputSurfaceState state) { |
| 62 switch (state) { | 61 switch (state) { |
| 62 case OUTPUT_SURFACE_NONE: |
| 63 return "OUTPUT_SURFACE_NONE"; |
| 63 case OUTPUT_SURFACE_ACTIVE: | 64 case OUTPUT_SURFACE_ACTIVE: |
| 64 return "OUTPUT_SURFACE_ACTIVE"; | 65 return "OUTPUT_SURFACE_ACTIVE"; |
| 65 case OUTPUT_SURFACE_LOST: | |
| 66 return "OUTPUT_SURFACE_LOST"; | |
| 67 case OUTPUT_SURFACE_CREATING: | 66 case OUTPUT_SURFACE_CREATING: |
| 68 return "OUTPUT_SURFACE_CREATING"; | 67 return "OUTPUT_SURFACE_CREATING"; |
| 69 case OUTPUT_SURFACE_WAITING_FOR_FIRST_COMMIT: | 68 case OUTPUT_SURFACE_WAITING_FOR_FIRST_COMMIT: |
| 70 return "OUTPUT_SURFACE_WAITING_FOR_FIRST_COMMIT"; | 69 return "OUTPUT_SURFACE_WAITING_FOR_FIRST_COMMIT"; |
| 71 case OUTPUT_SURFACE_WAITING_FOR_FIRST_ACTIVATION: | 70 case OUTPUT_SURFACE_WAITING_FOR_FIRST_ACTIVATION: |
| 72 return "OUTPUT_SURFACE_WAITING_FOR_FIRST_ACTIVATION"; | 71 return "OUTPUT_SURFACE_WAITING_FOR_FIRST_ACTIVATION"; |
| 73 } | 72 } |
| 74 NOTREACHED(); | 73 NOTREACHED(); |
| 75 return "???"; | 74 return "???"; |
| 76 } | 75 } |
| (...skipping 141 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 218 consecutive_checkerboard_animations_); | 217 consecutive_checkerboard_animations_); |
| 219 state->SetInteger("max_pending_swaps_", max_pending_swaps_); | 218 state->SetInteger("max_pending_swaps_", max_pending_swaps_); |
| 220 state->SetInteger("pending_swaps_", pending_swaps_); | 219 state->SetInteger("pending_swaps_", pending_swaps_); |
| 221 state->SetInteger("swaps_with_current_output_surface", | 220 state->SetInteger("swaps_with_current_output_surface", |
| 222 swaps_with_current_output_surface_); | 221 swaps_with_current_output_surface_); |
| 223 state->SetBoolean("needs_redraw", needs_redraw_); | 222 state->SetBoolean("needs_redraw", needs_redraw_); |
| 224 state->SetBoolean("needs_animate_", needs_animate_); | 223 state->SetBoolean("needs_animate_", needs_animate_); |
| 225 state->SetBoolean("needs_prepare_tiles", needs_prepare_tiles_); | 224 state->SetBoolean("needs_prepare_tiles", needs_prepare_tiles_); |
| 226 state->SetBoolean("needs_begin_main_frame", needs_begin_main_frame_); | 225 state->SetBoolean("needs_begin_main_frame", needs_begin_main_frame_); |
| 227 state->SetBoolean("visible", visible_); | 226 state->SetBoolean("visible", visible_); |
| 228 state->SetBoolean("can_start", can_start_); | |
| 229 state->SetBoolean("can_draw", can_draw_); | 227 state->SetBoolean("can_draw", can_draw_); |
| 230 state->SetBoolean("has_pending_tree", has_pending_tree_); | 228 state->SetBoolean("has_pending_tree", has_pending_tree_); |
| 231 state->SetBoolean("pending_tree_is_ready_for_activation", | 229 state->SetBoolean("pending_tree_is_ready_for_activation", |
| 232 pending_tree_is_ready_for_activation_); | 230 pending_tree_is_ready_for_activation_); |
| 233 state->SetBoolean("active_tree_needs_first_draw", | 231 state->SetBoolean("active_tree_needs_first_draw", |
| 234 active_tree_needs_first_draw_); | 232 active_tree_needs_first_draw_); |
| 235 state->SetBoolean("wait_for_ready_to_draw", wait_for_ready_to_draw_); | 233 state->SetBoolean("wait_for_ready_to_draw", wait_for_ready_to_draw_); |
| 236 state->SetBoolean("did_create_and_initialize_first_output_surface", | 234 state->SetBoolean("did_create_and_initialize_first_output_surface", |
| 237 did_create_and_initialize_first_output_surface_); | 235 did_create_and_initialize_first_output_surface_); |
| 238 state->SetBoolean("impl_latency_takes_priority", | 236 state->SetBoolean("impl_latency_takes_priority", |
| (...skipping 11 matching lines...) Expand all Loading... |
| 250 state->SetBoolean("did_perform_swap_in_last_draw", | 248 state->SetBoolean("did_perform_swap_in_last_draw", |
| 251 did_perform_swap_in_last_draw_); | 249 did_perform_swap_in_last_draw_); |
| 252 state->EndDictionary(); | 250 state->EndDictionary(); |
| 253 } | 251 } |
| 254 | 252 |
| 255 bool SchedulerStateMachine::PendingDrawsShouldBeAborted() const { | 253 bool SchedulerStateMachine::PendingDrawsShouldBeAborted() const { |
| 256 // Normally when |visible_| is false, pending activations will be forced and | 254 // Normally when |visible_| is false, pending activations will be forced and |
| 257 // draws will be aborted. However, when the embedder is Android WebView, | 255 // draws will be aborted. However, when the embedder is Android WebView, |
| 258 // software draws could be scheduled by the Android OS at any time and draws | 256 // software draws could be scheduled by the Android OS at any time and draws |
| 259 // should not be aborted in this case. | 257 // should not be aborted in this case. |
| 260 bool is_output_surface_lost = (output_surface_state_ == OUTPUT_SURFACE_LOST); | 258 bool is_output_surface_lost = (output_surface_state_ == OUTPUT_SURFACE_NONE); |
| 261 if (settings_.using_synchronous_renderer_compositor) | 259 if (settings_.using_synchronous_renderer_compositor) |
| 262 return is_output_surface_lost || !can_draw_; | 260 return is_output_surface_lost || !can_draw_; |
| 263 | 261 |
| 264 // These are all the cases where we normally cannot or do not want to draw | 262 // These are all the cases where we normally cannot or do not want to draw |
| 265 // but, if needs_redraw_ is true and we do not draw to make forward progress, | 263 // but, if needs_redraw_ is true and we do not draw to make forward progress, |
| 266 // we might deadlock with the main thread. | 264 // we might deadlock with the main thread. |
| 267 // This should be a superset of PendingActivationsShouldBeForced() since | 265 // This should be a superset of PendingActivationsShouldBeForced() since |
| 268 // activation of the pending tree is blocked by drawing of the active tree and | 266 // activation of the pending tree is blocked by drawing of the active tree and |
| 269 // the main thread might be blocked on activation of the most recent commit. | 267 // the main thread might be blocked on activation of the most recent commit. |
| 270 return is_output_surface_lost || !can_draw_ || !visible_; | 268 return is_output_surface_lost || !can_draw_ || !visible_; |
| 271 } | 269 } |
| 272 | 270 |
| 273 bool SchedulerStateMachine::PendingActivationsShouldBeForced() const { | 271 bool SchedulerStateMachine::PendingActivationsShouldBeForced() const { |
| 274 // There is no output surface to trigger our activations. | 272 // There is no output surface to trigger our activations. |
| 275 // If we do not force activations to make forward progress, we might deadlock | 273 // If we do not force activations to make forward progress, we might deadlock |
| 276 // with the main thread. | 274 // with the main thread. |
| 277 if (output_surface_state_ == OUTPUT_SURFACE_LOST) | 275 if (output_surface_state_ == OUTPUT_SURFACE_NONE) |
| 278 return true; | 276 return true; |
| 279 | 277 |
| 280 // If we're not visible, we should force activation. | 278 // If we're not visible, we should force activation. |
| 281 // Since we set RequiresHighResToDraw when becoming visible, we ensure that we | 279 // Since we set RequiresHighResToDraw when becoming visible, we ensure that we |
| 282 // don't checkerboard until all visible resources are done. Furthermore, if we | 280 // don't checkerboard until all visible resources are done. Furthermore, if we |
| 283 // do keep the pending tree around, when becoming visible we might activate | 281 // do keep the pending tree around, when becoming visible we might activate |
| 284 // prematurely causing RequiresHighResToDraw flag to be reset. In all cases, | 282 // prematurely causing RequiresHighResToDraw flag to be reset. In all cases, |
| 285 // we can simply activate on becoming invisible since we don't need to draw | 283 // we can simply activate on becoming invisible since we don't need to draw |
| 286 // the active tree when we're in this state. | 284 // the active tree when we're in this state. |
| 287 if (!visible_) | 285 if (!visible_) |
| 288 return true; | 286 return true; |
| 289 | 287 |
| 290 return false; | 288 return false; |
| 291 } | 289 } |
| 292 | 290 |
| 293 bool SchedulerStateMachine::ShouldBeginOutputSurfaceCreation() const { | 291 bool SchedulerStateMachine::ShouldBeginOutputSurfaceCreation() const { |
| 294 if (!visible_) | 292 if (!visible_) |
| 295 return false; | 293 return false; |
| 296 | 294 |
| 297 // Don't try to initialize too early. | |
| 298 if (!can_start_) | |
| 299 return false; | |
| 300 | |
| 301 // We only want to start output surface initialization after the | 295 // We only want to start output surface initialization after the |
| 302 // previous commit is complete. | 296 // previous commit is complete. |
| 303 if (begin_main_frame_state_ != BEGIN_MAIN_FRAME_STATE_IDLE) | 297 if (begin_main_frame_state_ != BEGIN_MAIN_FRAME_STATE_IDLE) |
| 304 return false; | 298 return false; |
| 305 | 299 |
| 306 // Make sure the BeginImplFrame from any previous OutputSurfaces | 300 // Make sure the BeginImplFrame from any previous OutputSurfaces |
| 307 // are complete before creating the new OutputSurface. | 301 // are complete before creating the new OutputSurface. |
| 308 if (begin_impl_frame_state_ != BEGIN_IMPL_FRAME_STATE_IDLE) | 302 if (begin_impl_frame_state_ != BEGIN_IMPL_FRAME_STATE_IDLE) |
| 309 return false; | 303 return false; |
| 310 | 304 |
| 311 // We want to clear the pipeline of any pending draws and activations | 305 // We want to clear the pipeline of any pending draws and activations |
| 312 // before starting output surface initialization. This allows us to avoid | 306 // before starting output surface initialization. This allows us to avoid |
| 313 // weird corner cases where we abort draws or force activation while we | 307 // weird corner cases where we abort draws or force activation while we |
| 314 // are initializing the output surface. | 308 // are initializing the output surface. |
| 315 if (active_tree_needs_first_draw_ || has_pending_tree_) | 309 if (active_tree_needs_first_draw_ || has_pending_tree_) |
| 316 return false; | 310 return false; |
| 317 | 311 |
| 318 // We need to create the output surface if we don't have one and we haven't | 312 // We need to create the output surface if we don't have one and we haven't |
| 319 // started creating one yet. | 313 // started creating one yet. |
| 320 return output_surface_state_ == OUTPUT_SURFACE_LOST; | 314 return output_surface_state_ == OUTPUT_SURFACE_NONE; |
| 321 } | 315 } |
| 322 | 316 |
| 323 bool SchedulerStateMachine::ShouldDraw() const { | 317 bool SchedulerStateMachine::ShouldDraw() const { |
| 324 // If we need to abort draws, we should do so ASAP since the draw could | 318 // If we need to abort draws, we should do so ASAP since the draw could |
| 325 // be blocking other important actions (like output surface initialization), | 319 // be blocking other important actions (like output surface initialization), |
| 326 // from occurring. If we are waiting for the first draw, then perform the | 320 // from occurring. If we are waiting for the first draw, then perform the |
| 327 // aborted draw to keep things moving. If we are not waiting for the first | 321 // aborted draw to keep things moving. If we are not waiting for the first |
| 328 // draw however, we don't want to abort for no reason. | 322 // draw however, we don't want to abort for no reason. |
| 329 if (PendingDrawsShouldBeAborted()) | 323 if (PendingDrawsShouldBeAborted()) |
| 330 return active_tree_needs_first_draw_; | 324 return active_tree_needs_first_draw_; |
| (...skipping 338 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 669 did_request_swap_in_last_frame_ = true; | 663 did_request_swap_in_last_frame_ = true; |
| 670 last_frame_number_swap_requested_ = current_frame_number_; | 664 last_frame_number_swap_requested_ = current_frame_number_; |
| 671 } | 665 } |
| 672 } | 666 } |
| 673 | 667 |
| 674 void SchedulerStateMachine::WillPrepareTiles() { | 668 void SchedulerStateMachine::WillPrepareTiles() { |
| 675 needs_prepare_tiles_ = false; | 669 needs_prepare_tiles_ = false; |
| 676 } | 670 } |
| 677 | 671 |
| 678 void SchedulerStateMachine::WillBeginOutputSurfaceCreation() { | 672 void SchedulerStateMachine::WillBeginOutputSurfaceCreation() { |
| 679 DCHECK_EQ(output_surface_state_, OUTPUT_SURFACE_LOST); | 673 DCHECK_EQ(output_surface_state_, OUTPUT_SURFACE_NONE); |
| 680 output_surface_state_ = OUTPUT_SURFACE_CREATING; | 674 output_surface_state_ = OUTPUT_SURFACE_CREATING; |
| 681 | 675 |
| 682 // The following DCHECKs make sure we are in the proper quiescent state. | 676 // The following DCHECKs make sure we are in the proper quiescent state. |
| 683 // The pipeline should be flushed entirely before we start output | 677 // The pipeline should be flushed entirely before we start output |
| 684 // surface creation to avoid complicated corner cases. | 678 // surface creation to avoid complicated corner cases. |
| 685 DCHECK_EQ(begin_main_frame_state_, BEGIN_MAIN_FRAME_STATE_IDLE); | 679 DCHECK_EQ(begin_main_frame_state_, BEGIN_MAIN_FRAME_STATE_IDLE); |
| 686 DCHECK(!has_pending_tree_); | 680 DCHECK(!has_pending_tree_); |
| 687 DCHECK(!active_tree_needs_first_draw_); | 681 DCHECK(!active_tree_needs_first_draw_); |
| 688 } | 682 } |
| 689 | 683 |
| (...skipping 366 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1056 } | 1050 } |
| 1057 } | 1051 } |
| 1058 | 1052 |
| 1059 void SchedulerStateMachine::DidPrepareTiles() { | 1053 void SchedulerStateMachine::DidPrepareTiles() { |
| 1060 needs_prepare_tiles_ = false; | 1054 needs_prepare_tiles_ = false; |
| 1061 // "Fill" the PrepareTiles funnel. | 1055 // "Fill" the PrepareTiles funnel. |
| 1062 prepare_tiles_funnel_++; | 1056 prepare_tiles_funnel_++; |
| 1063 } | 1057 } |
| 1064 | 1058 |
| 1065 void SchedulerStateMachine::DidLoseOutputSurface() { | 1059 void SchedulerStateMachine::DidLoseOutputSurface() { |
| 1066 if (output_surface_state_ == OUTPUT_SURFACE_LOST || | 1060 if (output_surface_state_ == OUTPUT_SURFACE_NONE || |
| 1067 output_surface_state_ == OUTPUT_SURFACE_CREATING) | 1061 output_surface_state_ == OUTPUT_SURFACE_CREATING) |
| 1068 return; | 1062 return; |
| 1069 output_surface_state_ = OUTPUT_SURFACE_LOST; | 1063 output_surface_state_ = OUTPUT_SURFACE_NONE; |
| 1070 needs_redraw_ = false; | 1064 needs_redraw_ = false; |
| 1071 wait_for_ready_to_draw_ = false; | 1065 wait_for_ready_to_draw_ = false; |
| 1072 } | 1066 } |
| 1073 | 1067 |
| 1074 void SchedulerStateMachine::NotifyReadyToActivate() { | 1068 void SchedulerStateMachine::NotifyReadyToActivate() { |
| 1075 if (has_pending_tree_) | 1069 if (has_pending_tree_) |
| 1076 pending_tree_is_ready_for_activation_ = true; | 1070 pending_tree_is_ready_for_activation_ = true; |
| 1077 } | 1071 } |
| 1078 | 1072 |
| 1079 void SchedulerStateMachine::NotifyReadyToDraw() { | 1073 void SchedulerStateMachine::NotifyReadyToDraw() { |
| (...skipping 15 matching lines...) Expand all Loading... |
| 1095 main_thread_missed_last_deadline_ = false; | 1089 main_thread_missed_last_deadline_ = false; |
| 1096 } | 1090 } |
| 1097 | 1091 |
| 1098 void SchedulerStateMachine::NotifyBeginMainFrameStarted() { | 1092 void SchedulerStateMachine::NotifyBeginMainFrameStarted() { |
| 1099 DCHECK_EQ(begin_main_frame_state_, BEGIN_MAIN_FRAME_STATE_SENT); | 1093 DCHECK_EQ(begin_main_frame_state_, BEGIN_MAIN_FRAME_STATE_SENT); |
| 1100 begin_main_frame_state_ = BEGIN_MAIN_FRAME_STATE_STARTED; | 1094 begin_main_frame_state_ = BEGIN_MAIN_FRAME_STATE_STARTED; |
| 1101 } | 1095 } |
| 1102 | 1096 |
| 1103 bool SchedulerStateMachine::HasInitializedOutputSurface() const { | 1097 bool SchedulerStateMachine::HasInitializedOutputSurface() const { |
| 1104 switch (output_surface_state_) { | 1098 switch (output_surface_state_) { |
| 1105 case OUTPUT_SURFACE_LOST: | 1099 case OUTPUT_SURFACE_NONE: |
| 1106 case OUTPUT_SURFACE_CREATING: | 1100 case OUTPUT_SURFACE_CREATING: |
| 1107 return false; | 1101 return false; |
| 1108 | 1102 |
| 1109 case OUTPUT_SURFACE_ACTIVE: | 1103 case OUTPUT_SURFACE_ACTIVE: |
| 1110 case OUTPUT_SURFACE_WAITING_FOR_FIRST_COMMIT: | 1104 case OUTPUT_SURFACE_WAITING_FOR_FIRST_COMMIT: |
| 1111 case OUTPUT_SURFACE_WAITING_FOR_FIRST_ACTIVATION: | 1105 case OUTPUT_SURFACE_WAITING_FOR_FIRST_ACTIVATION: |
| 1112 return true; | 1106 return true; |
| 1113 } | 1107 } |
| 1114 NOTREACHED(); | 1108 NOTREACHED(); |
| 1115 return false; | 1109 return false; |
| 1116 } | 1110 } |
| 1117 | 1111 |
| 1118 } // namespace cc | 1112 } // namespace cc |
| OLD | NEW |