Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 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 "ash/laser/laser_pointer_view.h" | 5 #include "ash/laser/laser_pointer_view.h" |
| 6 | 6 |
| 7 #include <GLES2/gl2.h> | 7 #include <GLES2/gl2.h> |
| 8 #include <GLES2/gl2ext.h> | 8 #include <GLES2/gl2ext.h> |
| 9 #include <GLES2/gl2extchromium.h> | 9 #include <GLES2/gl2extchromium.h> |
| 10 | 10 |
| 11 #include <algorithm> | |
| 12 #include <array> | |
| 13 #include <cmath> | |
| 11 #include <memory> | 14 #include <memory> |
| 12 | 15 |
| 13 #include "ash/laser/laser_pointer_points.h" | 16 #include "ash/laser/laser_pointer_points.h" |
| 14 #include "ash/laser/laser_segment_utils.h" | 17 #include "ash/laser/laser_segment_utils.h" |
| 15 #include "ash/public/cpp/shell_window_ids.h" | 18 #include "ash/public/cpp/shell_window_ids.h" |
| 16 #include "ash/shell.h" | 19 #include "ash/shell.h" |
| 20 #include "base/containers/adapters.h" | |
| 17 #include "base/threading/thread_task_runner_handle.h" | 21 #include "base/threading/thread_task_runner_handle.h" |
| 18 #include "base/timer/timer.h" | 22 #include "base/timer/timer.h" |
| 19 #include "base/trace_event/trace_event.h" | 23 #include "base/trace_event/trace_event.h" |
| 20 #include "cc/output/context_provider.h" | 24 #include "cc/output/context_provider.h" |
| 21 #include "cc/quads/texture_draw_quad.h" | 25 #include "cc/quads/texture_draw_quad.h" |
| 22 #include "cc/resources/transferable_resource.h" | 26 #include "cc/resources/transferable_resource.h" |
| 23 #include "cc/surfaces/surface.h" | 27 #include "cc/surfaces/surface.h" |
| 24 #include "cc/surfaces/surface_manager.h" | 28 #include "cc/surfaces/surface_manager.h" |
| 25 #include "gpu/command_buffer/client/context_support.h" | 29 #include "gpu/command_buffer/client/context_support.h" |
| 26 #include "gpu/command_buffer/client/gles2_interface.h" | 30 #include "gpu/command_buffer/client/gles2_interface.h" |
| (...skipping 11 matching lines...) Expand all Loading... | |
| 38 | 42 |
| 39 namespace ash { | 43 namespace ash { |
| 40 namespace { | 44 namespace { |
| 41 | 45 |
| 42 // Variables for rendering the laser. Radius in DIP. | 46 // Variables for rendering the laser. Radius in DIP. |
| 43 const float kPointInitialRadius = 5.0f; | 47 const float kPointInitialRadius = 5.0f; |
| 44 const float kPointFinalRadius = 0.25f; | 48 const float kPointFinalRadius = 0.25f; |
| 45 const int kPointInitialOpacity = 200; | 49 const int kPointInitialOpacity = 200; |
| 46 const int kPointFinalOpacity = 10; | 50 const int kPointFinalOpacity = 10; |
| 47 const SkColor kPointColor = SkColorSetRGB(255, 0, 0); | 51 const SkColor kPointColor = SkColorSetRGB(255, 0, 0); |
| 52 // Change this to a debug prediction code. | |
| 53 const SkColor kPredictionPointColor = SkColorSetRGB(255, 0, 0); | |
|
Daniele Castagna
2017/03/15 19:07:28
nit: you could initialize this to kPointColor to m
reveman
2017/03/16 12:57:28
Done.
| |
| 48 | 54 |
| 49 float DistanceBetweenPoints(const gfx::PointF& point1, | 55 float DistanceBetweenPoints(const gfx::PointF& point1, |
| 50 const gfx::PointF& point2) { | 56 const gfx::PointF& point2) { |
| 51 return (point1 - point2).Length(); | 57 return (point1 - point2).Length(); |
| 52 } | 58 } |
| 53 | 59 |
| 54 float LinearInterpolate(float initial_value, | 60 float LinearInterpolate(float initial_value, |
| 55 float final_value, | 61 float final_value, |
| 56 float progress) { | 62 float progress) { |
| 57 return initial_value + (final_value - initial_value) * progress; | 63 return initial_value + (final_value - initial_value) * progress; |
| (...skipping 131 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 189 } | 195 } |
| 190 } | 196 } |
| 191 scoped_refptr<cc::ContextProvider> context_provider; | 197 scoped_refptr<cc::ContextProvider> context_provider; |
| 192 uint32_t texture = 0; | 198 uint32_t texture = 0; |
| 193 uint32_t image = 0; | 199 uint32_t image = 0; |
| 194 gpu::Mailbox mailbox; | 200 gpu::Mailbox mailbox; |
| 195 }; | 201 }; |
| 196 | 202 |
| 197 // LaserPointerView | 203 // LaserPointerView |
| 198 LaserPointerView::LaserPointerView(base::TimeDelta life_duration, | 204 LaserPointerView::LaserPointerView(base::TimeDelta life_duration, |
| 205 base::TimeDelta presentation_delay, | |
| 199 aura::Window* root_window) | 206 aura::Window* root_window) |
| 200 : laser_points_(life_duration), | 207 : laser_points_(life_duration), |
| 208 predicted_laser_points_(life_duration), | |
| 209 presentation_delay_(presentation_delay), | |
| 201 frame_sink_id_(aura::Env::GetInstance() | 210 frame_sink_id_(aura::Env::GetInstance() |
| 202 ->context_factory_private() | 211 ->context_factory_private() |
| 203 ->AllocateFrameSinkId()), | 212 ->AllocateFrameSinkId()), |
| 204 frame_sink_support_(this, | 213 frame_sink_support_(this, |
| 205 aura::Env::GetInstance() | 214 aura::Env::GetInstance() |
| 206 ->context_factory_private() | 215 ->context_factory_private() |
| 207 ->GetSurfaceManager(), | 216 ->GetSurfaceManager(), |
| 208 frame_sink_id_, | 217 frame_sink_id_, |
| 209 false /* is_root */, | 218 false /* is_root */, |
| 210 true /* handles_frame_sink_id_invalidation */, | 219 true /* handles_frame_sink_id_invalidation */, |
| (...skipping 24 matching lines...) Expand all Loading... | |
| 235 | 244 |
| 236 LaserPointerView::~LaserPointerView() { | 245 LaserPointerView::~LaserPointerView() { |
| 237 // Make sure GPU memory buffer is unmapped before being destroyed. | 246 // Make sure GPU memory buffer is unmapped before being destroyed. |
| 238 if (gpu_memory_buffer_) | 247 if (gpu_memory_buffer_) |
| 239 gpu_memory_buffer_->Unmap(); | 248 gpu_memory_buffer_->Unmap(); |
| 240 } | 249 } |
| 241 | 250 |
| 242 void LaserPointerView::Stop() { | 251 void LaserPointerView::Stop() { |
| 243 buffer_damage_rect_.Union(GetBoundingBox()); | 252 buffer_damage_rect_.Union(GetBoundingBox()); |
| 244 laser_points_.Clear(); | 253 laser_points_.Clear(); |
| 254 predicted_laser_points_.Clear(); | |
| 245 OnPointsUpdated(); | 255 OnPointsUpdated(); |
| 246 } | 256 } |
| 247 | 257 |
| 248 void LaserPointerView::AddNewPoint(const gfx::PointF& new_point) { | 258 void LaserPointerView::AddNewPoint(const gfx::PointF& new_point, |
| 259 const base::TimeTicks& new_time) { | |
| 260 TRACE_EVENT1("ui", "LaserPointerView::AddNewPoint", "new_point", | |
| 261 new_point.ToString()); | |
| 262 TRACE_COUNTER1( | |
| 263 "ui", "LaserPointerPredictionError", | |
| 264 predicted_laser_points_.GetNumberOfPoints() | |
| 265 ? std::round((new_point - | |
| 266 predicted_laser_points_.laser_points().front().location) | |
| 267 .Length()) | |
| 268 : 0); | |
| 269 | |
| 249 buffer_damage_rect_.Union(GetBoundingBox()); | 270 buffer_damage_rect_.Union(GetBoundingBox()); |
| 250 laser_points_.AddPoint(new_point); | 271 laser_points_.AddPoint(new_point, new_time); |
| 272 | |
| 273 // Current time is needed to determine presentation time and the number of | |
| 274 // predicted points to add. | |
| 275 base::TimeTicks current_time = base::TimeTicks::Now(); | |
| 276 | |
| 277 // Create a new set of predicted points based on the last four points added. | |
| 278 // We add enough predicted points to fill the time between the new point and | |
| 279 // the expected presentation time. Note that estimated presentation time is | |
| 280 // based on current time and inefficient rendering of points can result in an | |
| 281 // actual presentation time that is later. | |
| 282 predicted_laser_points_.Clear(); | |
|
Daniele Castagna
2017/03/15 19:07:28
This probably creates a lot of discontinuity, sinc
reveman
2017/03/16 12:57:29
Yes, there's definitely room for improvement here.
| |
| 283 | |
| 284 // Normalize all coordinates to screen size. | |
| 285 gfx::Size screen_size = widget_->GetNativeView()->GetBoundsInScreen().size(); | |
| 286 gfx::Vector2dF scale(1.0f / screen_size.width(), 1.0f / screen_size.height()); | |
| 287 | |
| 288 // TODO(reveman): Determine interval based on history when event time stamps | |
| 289 // are accurate. b/36137953 | |
| 290 const float kPredictionIntervalMs = 5.0f; | |
| 291 const float kMaxPointIntervalMs = 10.0f; | |
| 292 base::TimeDelta prediction_interval = | |
| 293 base::TimeDelta::FromMilliseconds(kPredictionIntervalMs); | |
| 294 base::TimeDelta max_point_interval = | |
| 295 base::TimeDelta::FromMilliseconds(kMaxPointIntervalMs); | |
| 296 base::TimeTicks last_point_time = current_time; | |
| 297 | |
| 298 // Use the last four points for prediction. | |
| 299 using PositionArray = std::array<gfx::PointF, 4>; | |
| 300 PositionArray position; | |
|
Daniele Castagna
2017/03/15 19:07:28
nit: positions?
reveman
2017/03/16 12:57:28
then it should be velocities and accelerations too
| |
| 301 PositionArray::iterator it = position.begin(); | |
| 302 for (auto& point : base::Reversed(laser_points_.laser_points())) { | |
| 303 // Stop adding positons if interval between points is too large to provide | |
| 304 // an accurate history for prediction. | |
| 305 if ((last_point_time - point.time) > max_point_interval) | |
| 306 break; | |
| 307 | |
| 308 *it++ = gfx::ScalePoint(point.location, scale.x(), scale.y()); | |
| 309 last_point_time = point.time; | |
| 310 | |
| 311 // Stop when no more positions are needed. | |
| 312 if (it == position.end()) | |
| 313 break; | |
| 314 } | |
| 315 // Pad with last point if needed. | |
| 316 std::fill(it, position.end(), *(it - 1)); | |
| 317 | |
| 318 // Calculate velocity. | |
| 319 gfx::Vector2dF velocity[3]; | |
| 320 for (size_t i = 0; i < arraysize(velocity); ++i) | |
| 321 velocity[i] = position[i] - position[i + 1]; | |
|
Daniele Castagna
2017/03/15 19:07:28
It's really weird to see a velocity defined as del
reveman
2017/03/16 12:57:28
I agree. Added a comment and about this for now. W
| |
| 322 | |
| 323 // Calculate acceleration. | |
| 324 gfx::Vector2dF acceleration[2]; | |
| 325 for (size_t i = 0; i < arraysize(acceleration); ++i) | |
| 326 acceleration[i] = velocity[i] - velocity[i + 1]; | |
| 327 | |
| 328 // Calculate jerk. | |
| 329 gfx::Vector2dF jerk = acceleration[0] - acceleration[1]; | |
| 330 | |
| 331 // Adjust max prediction time based on speed as prediction data is not great | |
| 332 // at lower speeds. | |
| 333 const float kMaxPredictionScaleSpeed = 1e-5; | |
| 334 double speed = velocity[0].LengthSquared(); | |
| 335 base::TimeTicks max_prediction_time = | |
| 336 current_time + | |
| 337 std::min(presentation_delay_ * (speed / kMaxPredictionScaleSpeed), | |
| 338 presentation_delay_); | |
| 339 | |
| 340 // Add predicted points until we reach the max prediction time. | |
| 341 gfx::PointF location = position[0]; | |
| 342 for (base::TimeTicks time = new_time + prediction_interval; | |
| 343 time < max_prediction_time; time += prediction_interval) { | |
| 344 velocity[0] += acceleration[0]; | |
|
Daniele Castagna
2017/03/15 19:07:28
Again, kinda weird to see a velocity incremented b
reveman
2017/03/16 12:57:28
Added a comment for now.
| |
| 345 acceleration[0] += jerk; | |
|
Daniele Castagna
2017/03/15 19:07:28
Have you tried dampening jerk and acceleration at
reveman
2017/03/16 12:57:29
I considered that and suspect that it can help mak
| |
| 346 location += velocity[0]; | |
| 347 | |
| 348 predicted_laser_points_.AddPoint( | |
| 349 gfx::ScalePoint(location, screen_size.width(), screen_size.height()), | |
| 350 time); | |
| 351 | |
| 352 // Always stop at three predicted points as a four point history doesn't | |
| 353 // provide accurate prediction of more points. | |
| 354 if (predicted_laser_points_.GetNumberOfPoints() == 3) | |
| 355 break; | |
| 356 } | |
| 357 | |
| 358 // Move forward to next presentation time. | |
| 359 base::TimeTicks next_presentation_time = current_time + presentation_delay_; | |
| 360 laser_points_.MoveForwardToTime(next_presentation_time); | |
| 361 predicted_laser_points_.MoveForwardToTime(next_presentation_time); | |
| 362 | |
| 251 buffer_damage_rect_.Union(GetBoundingBox()); | 363 buffer_damage_rect_.Union(GetBoundingBox()); |
| 252 OnPointsUpdated(); | 364 OnPointsUpdated(); |
| 253 } | 365 } |
| 254 | 366 |
| 255 void LaserPointerView::UpdateTime() { | 367 void LaserPointerView::UpdateTime() { |
| 256 buffer_damage_rect_.Union(GetBoundingBox()); | 368 buffer_damage_rect_.Union(GetBoundingBox()); |
| 257 // Do not add the point but advance the time if the view is in process of | 369 // Do not add the point but advance the time if the view is in process of |
| 258 // fading away. | 370 // fading away. |
| 259 laser_points_.MoveForwardToTime(base::Time::Now()); | 371 base::TimeTicks next_presentation_time = |
| 372 base::TimeTicks::Now() + presentation_delay_; | |
| 373 laser_points_.MoveForwardToTime(next_presentation_time); | |
| 374 predicted_laser_points_.MoveForwardToTime(next_presentation_time); | |
| 260 buffer_damage_rect_.Union(GetBoundingBox()); | 375 buffer_damage_rect_.Union(GetBoundingBox()); |
| 261 OnPointsUpdated(); | 376 OnPointsUpdated(); |
| 262 } | 377 } |
| 263 | 378 |
| 264 void LaserPointerView::SetNeedsBeginFrame(bool needs_begin_frame) { | 379 void LaserPointerView::SetNeedsBeginFrame(bool needs_begin_frame) { |
| 265 frame_sink_support_.SetNeedsBeginFrame(needs_begin_frame); | 380 frame_sink_support_.SetNeedsBeginFrame(needs_begin_frame); |
| 266 } | 381 } |
| 267 | 382 |
| 268 void LaserPointerView::SubmitCompositorFrame( | 383 void LaserPointerView::SubmitCompositorFrame( |
| 269 const cc::LocalSurfaceId& local_surface_id, | 384 const cc::LocalSurfaceId& local_surface_id, |
| (...skipping 25 matching lines...) Expand all Loading... | |
| 295 gles2->WaitSyncTokenCHROMIUM(resources.front().sync_token.GetConstData()); | 410 gles2->WaitSyncTokenCHROMIUM(resources.front().sync_token.GetConstData()); |
| 296 | 411 |
| 297 if (!resources.front().lost) | 412 if (!resources.front().lost) |
| 298 returned_resources_.push_back(std::move(resource)); | 413 returned_resources_.push_back(std::move(resource)); |
| 299 } | 414 } |
| 300 | 415 |
| 301 gfx::Rect LaserPointerView::GetBoundingBox() { | 416 gfx::Rect LaserPointerView::GetBoundingBox() { |
| 302 // Expand the bounding box so that it includes the radius of the points on the | 417 // Expand the bounding box so that it includes the radius of the points on the |
| 303 // edges and antialiasing. | 418 // edges and antialiasing. |
| 304 gfx::Rect bounding_box = laser_points_.GetBoundingBox(); | 419 gfx::Rect bounding_box = laser_points_.GetBoundingBox(); |
| 420 bounding_box.Union(predicted_laser_points_.GetBoundingBox()); | |
| 305 const int kOutsetForAntialiasing = 1; | 421 const int kOutsetForAntialiasing = 1; |
| 306 int outset = kPointInitialRadius + kOutsetForAntialiasing; | 422 int outset = kPointInitialRadius + kOutsetForAntialiasing; |
| 307 bounding_box.Inset(-outset, -outset); | 423 bounding_box.Inset(-outset, -outset); |
| 308 return bounding_box; | 424 return bounding_box; |
| 309 } | 425 } |
| 310 | 426 |
| 311 void LaserPointerView::OnPointsUpdated() { | 427 void LaserPointerView::OnPointsUpdated() { |
| 312 if (pending_update_buffer_) | 428 if (pending_update_buffer_) |
| 313 return; | 429 return; |
| 314 | 430 |
| 315 pending_update_buffer_ = true; | 431 pending_update_buffer_ = true; |
| 316 base::ThreadTaskRunnerHandle::Get()->PostTask( | 432 base::ThreadTaskRunnerHandle::Get()->PostTask( |
| 317 FROM_HERE, base::Bind(&LaserPointerView::UpdateBuffer, | 433 FROM_HERE, base::Bind(&LaserPointerView::UpdateBuffer, |
| 318 weak_ptr_factory_.GetWeakPtr())); | 434 weak_ptr_factory_.GetWeakPtr())); |
| 319 } | 435 } |
| 320 | 436 |
| 321 void LaserPointerView::UpdateBuffer() { | 437 void LaserPointerView::UpdateBuffer() { |
| 322 TRACE_EVENT2("ui", "LaserPointerView::UpdatedBuffer", "damage", | 438 TRACE_EVENT1("ui", "LaserPointerView::UpdatedBuffer", "damage", |
| 323 buffer_damage_rect_.ToString(), "points", | 439 buffer_damage_rect_.ToString()); |
| 324 laser_points_.GetNumberOfPoints()); | |
| 325 | 440 |
| 326 DCHECK(pending_update_buffer_); | 441 DCHECK(pending_update_buffer_); |
| 327 pending_update_buffer_ = false; | 442 pending_update_buffer_ = false; |
| 328 | 443 |
| 329 gfx::Rect screen_bounds = widget_->GetNativeView()->GetBoundsInScreen(); | 444 gfx::Rect screen_bounds = widget_->GetNativeView()->GetBoundsInScreen(); |
| 330 gfx::Rect update_rect = buffer_damage_rect_; | 445 gfx::Rect update_rect = buffer_damage_rect_; |
| 331 buffer_damage_rect_ = gfx::Rect(); | 446 buffer_damage_rect_ = gfx::Rect(); |
| 332 | 447 |
| 333 // Create and map a single GPU memory buffer. The laser pointer will be | 448 // Create and map a single GPU memory buffer. The laser pointer will be |
| 334 // written into this buffer without any buffering. The result is that we | 449 // written into this buffer without any buffering. The result is that we |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 372 | 487 |
| 373 cc::PaintFlags flags; | 488 cc::PaintFlags flags; |
| 374 flags.setStyle(cc::PaintFlags::kFill_Style); | 489 flags.setStyle(cc::PaintFlags::kFill_Style); |
| 375 flags.setAntiAlias(true); | 490 flags.setAntiAlias(true); |
| 376 | 491 |
| 377 // Compute the offset of the current widget. | 492 // Compute the offset of the current widget. |
| 378 gfx::Vector2d widget_offset( | 493 gfx::Vector2d widget_offset( |
| 379 widget_->GetNativeView()->GetBoundsInRootWindow().origin().x(), | 494 widget_->GetNativeView()->GetBoundsInRootWindow().origin().x(), |
| 380 widget_->GetNativeView()->GetBoundsInRootWindow().origin().y()); | 495 widget_->GetNativeView()->GetBoundsInRootWindow().origin().y()); |
| 381 | 496 |
| 382 int num_points = laser_points_.GetNumberOfPoints(); | 497 int num_points = laser_points_.GetNumberOfPoints() + |
| 498 predicted_laser_points_.GetNumberOfPoints(); | |
| 383 if (num_points) { | 499 if (num_points) { |
| 384 LaserPointerPoints::LaserPoint previous_point = laser_points_.GetOldest(); | 500 LaserPointerPoints::LaserPoint previous_point = laser_points_.GetOldest(); |
| 385 previous_point.location -= widget_offset + update_rect.OffsetFromOrigin(); | 501 previous_point.location -= widget_offset + update_rect.OffsetFromOrigin(); |
| 386 LaserPointerPoints::LaserPoint current_point; | 502 LaserPointerPoints::LaserPoint current_point; |
| 387 std::vector<gfx::PointF> previous_segment_points; | 503 std::vector<gfx::PointF> previous_segment_points; |
| 388 float previous_radius; | 504 float previous_radius; |
| 389 int current_opacity; | 505 int current_opacity; |
| 390 | 506 |
| 391 for (int i = 0; i < num_points; ++i) { | 507 for (int i = 0; i < num_points; ++i) { |
| 392 current_point = laser_points_.laser_points()[i]; | 508 if (i < laser_points_.GetNumberOfPoints()) { |
| 509 current_point = laser_points_.laser_points()[i]; | |
| 510 } else { | |
| 511 current_point = | |
| 512 predicted_laser_points_ | |
| 513 .laser_points()[i - laser_points_.GetNumberOfPoints()]; | |
| 514 } | |
| 393 current_point.location -= widget_offset + update_rect.OffsetFromOrigin(); | 515 current_point.location -= widget_offset + update_rect.OffsetFromOrigin(); |
| 394 | 516 |
| 395 // Set the radius and opacity based on the distance. | 517 // Set the radius and opacity based on the distance. |
| 396 float current_radius = LinearInterpolate( | 518 float current_radius = LinearInterpolate( |
| 397 kPointInitialRadius, kPointFinalRadius, current_point.age); | 519 kPointInitialRadius, kPointFinalRadius, current_point.age); |
| 398 current_opacity = int{LinearInterpolate( | 520 current_opacity = int{LinearInterpolate( |
| 399 kPointInitialOpacity, kPointFinalOpacity, current_point.age)}; | 521 kPointInitialOpacity, kPointFinalOpacity, current_point.age)}; |
| 400 | 522 |
| 401 // If we draw laser_points_ that are within a stroke width of each other, | 523 // If we draw laser_points_ that are within a stroke width of each other, |
| 402 // the result will be very jagged, unless we are on the last point, then | 524 // the result will be very jagged, unless we are on the last point, then |
| 403 // we draw regardless. | 525 // we draw regardless. |
| 404 float distance_threshold = current_radius * 2.0f; | 526 float distance_threshold = current_radius * 2.0f; |
| 405 if (DistanceBetweenPoints(previous_point.location, | 527 if (DistanceBetweenPoints(previous_point.location, |
| 406 current_point.location) <= distance_threshold && | 528 current_point.location) <= distance_threshold && |
| 407 i != num_points - 1) { | 529 i != num_points - 1) { |
| 408 continue; | 530 continue; |
| 409 } | 531 } |
| 410 | 532 |
| 411 LaserSegment current_segment( | 533 LaserSegment current_segment( |
| 412 previous_segment_points, gfx::PointF(previous_point.location), | 534 previous_segment_points, gfx::PointF(previous_point.location), |
| 413 gfx::PointF(current_point.location), previous_radius, current_radius, | 535 gfx::PointF(current_point.location), previous_radius, current_radius, |
| 414 i == num_points - 1); | 536 i == num_points - 1); |
| 415 | 537 |
| 416 SkPath path = current_segment.path(); | 538 SkPath path = current_segment.path(); |
| 417 flags.setColor(SkColorSetA(kPointColor, current_opacity)); | 539 if (i < laser_points_.GetNumberOfPoints()) |
| 540 flags.setColor(SkColorSetA(kPointColor, current_opacity)); | |
| 541 else | |
| 542 flags.setColor(SkColorSetA(kPredictionPointColor, current_opacity)); | |
| 418 canvas.DrawPath(path, flags); | 543 canvas.DrawPath(path, flags); |
| 419 | 544 |
| 420 previous_segment_points = current_segment.path_points(); | 545 previous_segment_points = current_segment.path_points(); |
| 421 previous_radius = current_radius; | 546 previous_radius = current_radius; |
| 422 previous_point = current_point; | 547 previous_point = current_point; |
| 423 } | 548 } |
| 424 | 549 |
| 425 // Draw the last point as a circle. | 550 // Draw the last point as a circle. |
| 426 flags.setColor(SkColorSetA(kPointColor, current_opacity)); | |
| 427 flags.setStyle(cc::PaintFlags::kFill_Style); | 551 flags.setStyle(cc::PaintFlags::kFill_Style); |
| 428 canvas.DrawCircle(current_point.location, kPointInitialRadius, flags); | 552 canvas.DrawCircle(current_point.location, kPointInitialRadius, flags); |
| 429 } | 553 } |
| 430 | 554 |
| 431 // Copy result to GPU memory buffer. This is effectiely a memcpy and unlike | 555 // Copy result to GPU memory buffer. This is effectiely a memcpy and unlike |
| 432 // drawing to the buffer directly this ensures that the buffer is never in a | 556 // drawing to the buffer directly this ensures that the buffer is never in a |
| 433 // state that would result in flicker. | 557 // state that would result in flicker. |
| 434 { | 558 { |
| 435 TRACE_EVENT0("ui", "LaserPointerView::OnPointsUpdated::Copy"); | 559 TRACE_EVENT0("ui", "LaserPointerView::OnPointsUpdated::Copy"); |
| 436 | 560 |
| (...skipping 147 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 584 pending_draw_surface_ = true; | 708 pending_draw_surface_ = true; |
| 585 } | 709 } |
| 586 | 710 |
| 587 void LaserPointerView::OnDidDrawSurface() { | 711 void LaserPointerView::OnDidDrawSurface() { |
| 588 pending_draw_surface_ = false; | 712 pending_draw_surface_ = false; |
| 589 if (needs_update_surface_) | 713 if (needs_update_surface_) |
| 590 UpdateSurface(); | 714 UpdateSurface(); |
| 591 } | 715 } |
| 592 | 716 |
| 593 } // namespace ash | 717 } // namespace ash |
| OLD | NEW |