 Chromium Code Reviews
 Chromium Code Reviews Issue 1236463002:
  Vectorize download shelf progress indicators  (Closed) 
  Base URL: https://chromium.googlesource.com/chromium/src.git@master
    
  
    Issue 1236463002:
  Vectorize download shelf progress indicators  (Closed) 
  Base URL: https://chromium.googlesource.com/chromium/src.git@master| 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 #import "chrome/browser/ui/cocoa/download/download_item_cell.h" | 5 #import "chrome/browser/ui/cocoa/download/download_item_cell.h" | 
| 6 | 6 | 
| 7 #include "base/bind.h" | 7 #include "base/bind.h" | 
| 8 #include "base/strings/sys_string_conversions.h" | 8 #include "base/strings/sys_string_conversions.h" | 
| 9 #include "chrome/browser/download/download_item_model.h" | 9 #include "chrome/browser/download/download_item_model.h" | 
| 10 #include "chrome/browser/download/download_shelf.h" | 10 #include "chrome/browser/download/download_shelf.h" | 
| 11 #import "chrome/browser/themes/theme_properties.h" | 11 #import "chrome/browser/themes/theme_properties.h" | 
| 12 #import "chrome/browser/ui/cocoa/download/background_theme.h" | 12 #import "chrome/browser/ui/cocoa/download/background_theme.h" | 
| 13 #import "chrome/browser/ui/cocoa/themed_window.h" | 13 #import "chrome/browser/ui/cocoa/themed_window.h" | 
| 14 #include "content/public/browser/download_item.h" | 14 #include "content/public/browser/download_item.h" | 
| 15 #include "content/public/browser/download_manager.h" | 15 #include "content/public/browser/download_manager.h" | 
| 16 #include "grit/theme_resources.h" | 16 #include "grit/theme_resources.h" | 
| 17 #import "third_party/google_toolbox_for_mac/src/AppKit/GTMNSAnimation+Duration.h " | 17 #import "third_party/google_toolbox_for_mac/src/AppKit/GTMNSAnimation+Duration.h " | 
| 18 #import "third_party/google_toolbox_for_mac/src/AppKit/GTMNSColor+Luminance.h" | 18 #import "third_party/google_toolbox_for_mac/src/AppKit/GTMNSColor+Luminance.h" | 
| 19 #include "ui/base/default_theme_provider.h" | |
| 19 #include "ui/gfx/canvas_skia_paint.h" | 20 #include "ui/gfx/canvas_skia_paint.h" | 
| 20 #include "ui/gfx/font_list.h" | 21 #include "ui/gfx/font_list.h" | 
| 21 #include "ui/gfx/scoped_ns_graphics_context_save_gstate_mac.h" | 22 #include "ui/gfx/scoped_ns_graphics_context_save_gstate_mac.h" | 
| 22 #include "ui/gfx/text_elider.h" | 23 #include "ui/gfx/text_elider.h" | 
| 24 #include "ui/native_theme/native_theme.h" | |
| 23 | 25 | 
| 24 // Distance from top border to icon. | 26 // Distance from top border to icon. | 
| 25 const CGFloat kImagePaddingTop = 7; | 27 const CGFloat kImagePaddingTop = 7; | 
| 26 | 28 | 
| 27 // Distance from left border to icon. | 29 // Distance from left border to icon. | 
| 28 const CGFloat kImagePaddingLeft = 9; | 30 const CGFloat kImagePaddingLeft = 9; | 
| 29 | 31 | 
| 30 // Width of icon. | 32 // Width of icon. | 
| 31 const CGFloat kImageWidth = 16; | 33 const CGFloat kImageWidth = 16; | 
| 32 | 34 | 
| 33 // Height of icon. | 35 // Height of icon. | 
| 34 const CGFloat kImageHeight = 16; | 36 const CGFloat kImageHeight = 16; | 
| 35 | 37 | 
| 36 // x coordinate of download name string, in view coords. | 38 // x coordinate of download name string, in view coords. | 
| 37 const CGFloat kTextPosLeft = kImagePaddingLeft + | 39 const CGFloat kTextPosLeft = kImagePaddingLeft + | 
| 38 kImageWidth + DownloadShelf::kSmallProgressIconOffset; | 40 kImageWidth + DownloadShelf::kFiletypeIconOffset; | 
| 39 | 41 | 
| 40 // Distance from end of download name string to dropdown area. | 42 // Distance from end of download name string to dropdown area. | 
| 41 const CGFloat kTextPaddingRight = 3; | 43 const CGFloat kTextPaddingRight = 3; | 
| 42 | 44 | 
| 43 // y coordinate of download name string, in view coords, when status message | 45 // y coordinate of download name string, in view coords, when status message | 
| 44 // is visible. | 46 // is visible. | 
| 45 const CGFloat kPrimaryTextPosTop = 3; | 47 const CGFloat kPrimaryTextPosTop = 3; | 
| 46 | 48 | 
| 47 // y coordinate of download name string, in view coords, when status message | 49 // y coordinate of download name string, in view coords, when status message | 
| 48 // is not visible. | 50 // is not visible. | 
| (...skipping 20 matching lines...) Expand all Loading... | |
| 69 NSTimeInterval kHideStatusDuration = 0.3; | 71 NSTimeInterval kHideStatusDuration = 0.3; | 
| 70 | 72 | 
| 71 // Duration of the 'download complete' animation, in seconds. | 73 // Duration of the 'download complete' animation, in seconds. | 
| 72 const CGFloat kCompleteAnimationDuration = 2.5; | 74 const CGFloat kCompleteAnimationDuration = 2.5; | 
| 73 | 75 | 
| 74 // Duration of the 'download interrupted' animation, in seconds. | 76 // Duration of the 'download interrupted' animation, in seconds. | 
| 75 const CGFloat kInterruptedAnimationDuration = 2.5; | 77 const CGFloat kInterruptedAnimationDuration = 2.5; | 
| 76 | 78 | 
| 77 using content::DownloadItem; | 79 using content::DownloadItem; | 
| 78 | 80 | 
| 79 namespace { | |
| 80 | |
| 81 // Passed as a callback to DownloadShelf paint functions. On toolkit-views | |
| 82 // platforms it will mirror the position of the download progress, but that's | |
| 83 // not done on Mac. | |
| 84 void DummyRTLMirror(gfx::Rect* bounds) { | |
| 85 } | |
| 86 | |
| 87 } // namespace | |
| 88 | |
| 89 // This is a helper class to animate the fading out of the status text. | 81 // This is a helper class to animate the fading out of the status text. | 
| 90 @interface DownloadItemCellAnimation : NSAnimation { | 82 @interface DownloadItemCellAnimation : NSAnimation { | 
| 91 @private | 83 @private | 
| 92 DownloadItemCell* cell_; | 84 DownloadItemCell* cell_; | 
| 93 } | 85 } | 
| 94 - (id)initWithDownloadItemCell:(DownloadItemCell*)cell | 86 - (id)initWithDownloadItemCell:(DownloadItemCell*)cell | 
| 95 duration:(NSTimeInterval)duration | 87 duration:(NSTimeInterval)duration | 
| 96 animationCurve:(NSAnimationCurve)animationCurve; | 88 animationCurve:(NSAnimationCurve)animationCurve; | 
| 97 | 89 | 
| 98 @end | 90 @end | 
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 133 | 125 | 
| 134 @implementation DownloadItemCell | 126 @implementation DownloadItemCell | 
| 135 | 127 | 
| 136 @synthesize secondaryTitle = secondaryTitle_; | 128 @synthesize secondaryTitle = secondaryTitle_; | 
| 137 @synthesize secondaryFont = secondaryFont_; | 129 @synthesize secondaryFont = secondaryFont_; | 
| 138 | 130 | 
| 139 - (void)setInitialState { | 131 - (void)setInitialState { | 
| 140 isStatusTextVisible_ = NO; | 132 isStatusTextVisible_ = NO; | 
| 141 titleY_ = kPrimaryTextOnlyPosTop; | 133 titleY_ = kPrimaryTextOnlyPosTop; | 
| 142 statusAlpha_ = 0.0; | 134 statusAlpha_ = 0.0; | 
| 143 indeterminateProgressAngle_ = DownloadShelf::kStartAngleDegrees; | |
| 144 | 135 | 
| 145 [self setFont:[NSFont systemFontOfSize: | 136 [self setFont:[NSFont systemFontOfSize: | 
| 146 [NSFont systemFontSizeForControlSize:NSSmallControlSize]]]; | 137 [NSFont systemFontSizeForControlSize:NSSmallControlSize]]]; | 
| 147 [self setSecondaryFont:[NSFont systemFontOfSize: | 138 [self setSecondaryFont:[NSFont systemFontOfSize: | 
| 148 [NSFont systemFontSizeForControlSize:NSSmallControlSize]]]; | 139 [NSFont systemFontSizeForControlSize:NSSmallControlSize]]]; | 
| 149 | 140 | 
| 150 [self updateTrackingAreas:self]; | 141 [self updateTrackingAreas:self]; | 
| 151 [[NSNotificationCenter defaultCenter] | 142 [[NSNotificationCenter defaultCenter] | 
| 152 addObserver:self | 143 addObserver:self | 
| 153 selector:@selector(updateTrackingAreas:) | 144 selector:@selector(updateTrackingAreas:) | 
| (...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 245 break; | 236 break; | 
| 246 case DownloadItem::IN_PROGRESS: | 237 case DownloadItem::IN_PROGRESS: | 
| 247 if (downloadModel->download()->IsPaused()) { | 238 if (downloadModel->download()->IsPaused()) { | 
| 248 percentDone_ = -1; | 239 percentDone_ = -1; | 
| 249 [self stopIndeterminateAnimation]; | 240 [self stopIndeterminateAnimation]; | 
| 250 } else if (downloadModel->PercentComplete() == -1) { | 241 } else if (downloadModel->PercentComplete() == -1) { | 
| 251 percentDone_ = -1; | 242 percentDone_ = -1; | 
| 252 if (!indeterminateProgressTimer_) { | 243 if (!indeterminateProgressTimer_) { | 
| 253 indeterminateProgressTimer_.reset([[IndeterminateProgressTimer alloc] | 244 indeterminateProgressTimer_.reset([[IndeterminateProgressTimer alloc] | 
| 254 initWithDownloadItemCell:self]); | 245 initWithDownloadItemCell:self]); | 
| 246 progressStartTime_ = base::TimeTicks::Now(); | |
| 255 } | 247 } | 
| 256 } else { | 248 } else { | 
| 257 percentDone_ = downloadModel->PercentComplete(); | 249 percentDone_ = downloadModel->PercentComplete(); | 
| 258 [self stopIndeterminateAnimation]; | 250 [self stopIndeterminateAnimation]; | 
| 259 } | 251 } | 
| 260 break; | 252 break; | 
| 261 default: | 253 default: | 
| 262 NOTREACHED(); | 254 NOTREACHED(); | 
| 263 } | 255 } | 
| 264 | 256 | 
| (...skipping 281 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 546 [primaryText drawAtPoint:primaryPos withAttributes:primaryTextAttributes]; | 538 [primaryText drawAtPoint:primaryPos withAttributes:primaryTextAttributes]; | 
| 547 | 539 | 
| 548 // Draw progress disk | 540 // Draw progress disk | 
| 549 { | 541 { | 
| 550 // CanvasSkiaPaint draws its content to the current NSGraphicsContext in its | 542 // CanvasSkiaPaint draws its content to the current NSGraphicsContext in its | 
| 551 // destructor, which needs to be invoked before the icon is drawn below - | 543 // destructor, which needs to be invoked before the icon is drawn below - | 
| 552 // hence this nested block. | 544 // hence this nested block. | 
| 553 | 545 | 
| 554 // Always repaint the whole disk. | 546 // Always repaint the whole disk. | 
| 555 NSPoint imagePosition = [self imageRectForBounds:cellFrame].origin; | 547 NSPoint imagePosition = [self imageRectForBounds:cellFrame].origin; | 
| 556 int x = imagePosition.x - DownloadShelf::kSmallProgressIconOffset; | 548 int x = imagePosition.x - DownloadShelf::kFiletypeIconOffset; | 
| 557 int y = imagePosition.y - DownloadShelf::kSmallProgressIconOffset; | 549 int y = imagePosition.y - DownloadShelf::kFiletypeIconOffset; | 
| 558 NSRect dirtyRect = NSMakeRect( | 550 NSRect dirtyRect = NSMakeRect( | 
| 559 x, y, | 551 x, y, | 
| 560 DownloadShelf::kSmallProgressIconSize, | 552 DownloadShelf::kProgressIndicatorSize, | 
| 561 DownloadShelf::kSmallProgressIconSize); | 553 DownloadShelf::kProgressIndicatorSize); | 
| 562 | 554 | 
| 563 gfx::CanvasSkiaPaint canvas(dirtyRect, false); | 555 gfx::CanvasSkiaPaint canvas(dirtyRect, false); | 
| 564 canvas.set_composite_alpha(true); | 556 canvas.set_composite_alpha(true); | 
| 557 canvas.Translate(gfx::Vector2d(x, y)); | |
| 558 | |
| 559 ui::ThemeProvider* themeProvider = | |
| 560 [[[self controlView] window] themeProvider]; | |
| 561 ui::DefaultThemeProvider defaultTheme; | |
| 562 if (!themeProvider) | |
| 563 themeProvider = &defaultTheme; | |
| 
Evan Stade
2015/07/22 17:34:43
theme provider can be null during tests
 
asanka
2015/07/22 21:22:17
Can we instead mock the themeProvider selector on
 
Evan Stade
2015/07/22 21:32:20
That would be nice, except I don't have a mac buil
 | |
| 564 | |
| 565 if (completionAnimation_.get()) { | 565 if (completionAnimation_.get()) { | 
| 566 if ([completionAnimation_ isAnimating]) { | 566 if ([completionAnimation_ isAnimating]) { | 
| 567 if (percentDone_ == -1) { | 567 if (percentDone_ == -1) { | 
| 568 DownloadShelf::PaintDownloadComplete( | 568 DownloadShelf::PaintDownloadComplete( | 
| 569 &canvas, base::Bind(&DummyRTLMirror), x, y, | 569 &canvas, *themeProvider, | 
| 570 [completionAnimation_ currentValue]); | 570 [completionAnimation_ currentValue]); | 
| 571 } else { | 571 } else { | 
| 572 DownloadShelf::PaintDownloadInterrupted( | 572 DownloadShelf::PaintDownloadInterrupted( | 
| 573 &canvas, base::Bind(&DummyRTLMirror), x, y, | 573 &canvas, *themeProvider, | 
| 574 [completionAnimation_ currentValue]); | 574 [completionAnimation_ currentValue]); | 
| 575 } | 575 } | 
| 576 } | 576 } | 
| 577 } else if (percentDone_ >= 0 || indeterminateProgressTimer_) { | 577 } else if (percentDone_ >= 0 || indeterminateProgressTimer_) { | 
| 578 DownloadShelf::PaintDownloadProgress(&canvas, base::Bind(&DummyRTLMirror), | 578 DownloadShelf::PaintDownloadProgress( | 
| 579 x, y, indeterminateProgressAngle_, | 579 &canvas, *themeProvider, | 
| 580 percentDone_); | 580 progressStartTime_, percentDone_); | 
| 581 } | 581 } | 
| 582 } | 582 } | 
| 583 | 583 | 
| 584 // Draw icon | 584 // Draw icon | 
| 585 [[self image] drawInRect:[self imageRectForBounds:cellFrame] | 585 [[self image] drawInRect:[self imageRectForBounds:cellFrame] | 
| 586 fromRect:NSZeroRect | 586 fromRect:NSZeroRect | 
| 587 operation:NSCompositeSourceOver | 587 operation:NSCompositeSourceOver | 
| 588 fraction:[self isEnabled] ? 1.0 : 0.5 | 588 fraction:[self isEnabled] ? 1.0 : 0.5 | 
| 589 respectFlipped:YES | 589 respectFlipped:YES | 
| 590 hints:nil]; | 590 hints:nil]; | 
| (...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 682 (1 - progress)*kPrimaryTextPosTop; | 682 (1 - progress)*kPrimaryTextPosTop; | 
| 683 statusAlpha_ = 1 - progress; | 683 statusAlpha_ = 1 - progress; | 
| 684 } | 684 } | 
| 685 [[self controlView] setNeedsDisplay:YES]; | 685 [[self controlView] setNeedsDisplay:YES]; | 
| 686 } else if (animation == completionAnimation_) { | 686 } else if (animation == completionAnimation_) { | 
| 687 [[self controlView] setNeedsDisplay:YES]; | 687 [[self controlView] setNeedsDisplay:YES]; | 
| 688 } | 688 } | 
| 689 } | 689 } | 
| 690 | 690 | 
| 691 - (void)updateIndeterminateDownload { | 691 - (void)updateIndeterminateDownload { | 
| 692 indeterminateProgressAngle_ = | |
| 693 (indeterminateProgressAngle_ + DownloadShelf::kUnknownIncrementDegrees) % | |
| 694 DownloadShelf::kMaxDegrees; | |
| 695 [[self controlView] setNeedsDisplay:YES]; | 692 [[self controlView] setNeedsDisplay:YES]; | 
| 696 } | 693 } | 
| 697 | 694 | 
| 698 - (void)stopIndeterminateAnimation { | 695 - (void)stopIndeterminateAnimation { | 
| 699 [indeterminateProgressTimer_ invalidate]; | 696 [indeterminateProgressTimer_ invalidate]; | 
| 700 indeterminateProgressTimer_.reset(); | 697 indeterminateProgressTimer_.reset(); | 
| 701 } | 698 } | 
| 702 | 699 | 
| 703 - (void)animationDidEnd:(NSAnimation *)animation { | 700 - (void)animationDidEnd:(NSAnimation *)animation { | 
| 704 if (animation == toggleStatusVisibilityAnimation_) | 701 if (animation == toggleStatusVisibilityAnimation_) | 
| (...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 763 | 760 | 
| 764 - (void)invalidate { | 761 - (void)invalidate { | 
| 765 [timer_ invalidate]; | 762 [timer_ invalidate]; | 
| 766 } | 763 } | 
| 767 | 764 | 
| 768 - (void)onTimer:(NSTimer*)timer { | 765 - (void)onTimer:(NSTimer*)timer { | 
| 769 [cell_ updateIndeterminateDownload]; | 766 [cell_ updateIndeterminateDownload]; | 
| 770 } | 767 } | 
| 771 | 768 | 
| 772 @end | 769 @end | 
| OLD | NEW |