| OLD | NEW |
| 1 // Copyright 2012 The Chromium Authors. All rights reserved. | 1 // Copyright 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 // For performance reasons, the composition of the card frame is broken up into | 5 // For performance reasons, the composition of the card frame is broken up into |
| 6 // four pieces. The overall structure of the CardView is: | 6 // four pieces. The overall structure of the CardView is: |
| 7 // - CardView | 7 // - CardView |
| 8 // - Snapshot (UIImageView) | 8 // - Snapshot (UIImageView) |
| 9 // - FrameTop (UIImageView) | 9 // - FrameTop (UIImageView) |
| 10 // - FrameLeft (UIImageView) | 10 // - FrameLeft (UIImageView) |
| 11 // - FrameRight (UIImageView) | 11 // - FrameRight (UIImageView) |
| 12 // - FrameBottom (UIImageView) | 12 // - FrameBottom (UIImageView) |
| 13 // - CardTabView (UIView::DrawRect) | 13 // - CardTabView (UIView::DrawRect) |
| 14 // | 14 // |
| 15 // While it would be simpler to put the frame in one transparent UIImageView, | 15 // While it would be simpler to put the frame in one transparent UIImageView, |
| 16 // that would make the entire snapshot area needlessly color-blended. Instead | 16 // that would make the entire snapshot area needlessly color-blended. Instead |
| 17 // the frame is broken up into four pieces, top, left, bottom, right. | 17 // the frame is broken up into four pieces, top, left, bottom, right. |
| 18 // | 18 // |
| 19 // The frame's tab gets its own view above everything else (CardTabView) so that | 19 // The frame's tab gets its own view above everything else (CardTabView) so that |
| 20 // it can be animated out. It's also transparent since the tab has a curve and | 20 // it can be animated out. It's also transparent since the tab has a curve and |
| 21 // a shadow. | 21 // a shadow. |
| 22 | 22 |
| 23 #import "ios/chrome/browser/ui/stack_view/card_view.h" | 23 #import "ios/chrome/browser/ui/stack_view/card_view.h" |
| 24 | 24 |
| 25 #import <QuartzCore/QuartzCore.h> | 25 #import <QuartzCore/QuartzCore.h> |
| 26 #include <algorithm> | 26 #include <algorithm> |
| 27 | 27 |
| 28 #import "base/mac/foundation_util.h" | 28 #import "base/mac/foundation_util.h" |
| 29 #import "base/mac/objc_property_releaser.h" | 29 |
| 30 #import "base/mac/scoped_nsobject.h" | |
| 31 #include "components/strings/grit/components_strings.h" | 30 #include "components/strings/grit/components_strings.h" |
| 32 #import "ios/chrome/browser/ui/animation_util.h" | 31 #import "ios/chrome/browser/ui/animation_util.h" |
| 33 #import "ios/chrome/browser/ui/reversed_animation.h" | 32 #import "ios/chrome/browser/ui/reversed_animation.h" |
| 34 #import "ios/chrome/browser/ui/rtl_geometry.h" | 33 #import "ios/chrome/browser/ui/rtl_geometry.h" |
| 35 #import "ios/chrome/browser/ui/stack_view/close_button.h" | 34 #import "ios/chrome/browser/ui/stack_view/close_button.h" |
| 36 #import "ios/chrome/browser/ui/stack_view/title_label.h" | 35 #import "ios/chrome/browser/ui/stack_view/title_label.h" |
| 37 #import "ios/chrome/browser/ui/ui_util.h" | 36 #import "ios/chrome/browser/ui/ui_util.h" |
| 38 #import "ios/chrome/common/material_timing.h" | 37 #import "ios/chrome/common/material_timing.h" |
| 39 #import "ios/third_party/material_components_ios/src/components/Typography/src/M
aterialTypography.h" | 38 #import "ios/third_party/material_components_ios/src/components/Typography/src/M
aterialTypography.h" |
| 40 #include "ui/base/l10n/l10n_util.h" | 39 #include "ui/base/l10n/l10n_util.h" |
| 41 #include "ui/base/resource/resource_bundle.h" | 40 #include "ui/base/resource/resource_bundle.h" |
| 42 #include "ui/gfx/favicon_size.h" | 41 #include "ui/gfx/favicon_size.h" |
| 43 #include "ui/gfx/image/image.h" | 42 #include "ui/gfx/image/image.h" |
| 44 #import "ui/gfx/ios/uikit_util.h" | 43 #import "ui/gfx/ios/uikit_util.h" |
| 45 | 44 |
| 45 #if !defined(__has_feature) || !__has_feature(objc_arc) |
| 46 #error "This file requires ARC support." |
| 47 #endif |
| 48 |
| 46 using ios::material::TimingFunction; | 49 using ios::material::TimingFunction; |
| 47 | 50 |
| 48 const UIEdgeInsets kCardImageInsets = {48.0, 4.0, 4.0, 4.0}; | 51 const UIEdgeInsets kCardImageInsets = {48.0, 4.0, 4.0, 4.0}; |
| 49 const CGFloat kCardFrameInset = 1.0; | 52 const CGFloat kCardFrameInset = 1.0; |
| 50 const CGFloat kCardShadowThickness = 16.0; | 53 const CGFloat kCardShadowThickness = 16.0; |
| 51 const CGFloat kCardFrameCornerRadius = 4.0; | 54 const CGFloat kCardFrameCornerRadius = 4.0; |
| 52 const CGFloat kCardTabTopInset = 4; | 55 const CGFloat kCardTabTopInset = 4; |
| 53 const CGFloat kCardFrameBackgroundBrightness = 242.0 / 255.0; | 56 const CGFloat kCardFrameBackgroundBrightness = 242.0 / 255.0; |
| 54 const CGFloat kCardFrameBackgroundBrightnessIncognito = 80.0 / 255.0; | 57 const CGFloat kCardFrameBackgroundBrightnessIncognito = 80.0 / 255.0; |
| 55 const CGFloat kCardFrameImageSnapshotOverlap = 1.0; | 58 const CGFloat kCardFrameImageSnapshotOverlap = 1.0; |
| (...skipping 22 matching lines...) Expand all Loading... |
| 78 return [UIImage imageNamed:name]; | 81 return [UIImage imageNamed:name]; |
| 79 } | 82 } |
| 80 | 83 |
| 81 } // namespace | 84 } // namespace |
| 82 | 85 |
| 83 #pragma mark - | 86 #pragma mark - |
| 84 | 87 |
| 85 @interface CardTabView : UIView | 88 @interface CardTabView : UIView |
| 86 | 89 |
| 87 @property(nonatomic, assign) CardCloseButtonSide closeButtonSide; | 90 @property(nonatomic, assign) CardCloseButtonSide closeButtonSide; |
| 88 @property(nonatomic, retain) UIImageView* favIconView; | 91 @property(nonatomic, strong) UIImageView* favIconView; |
| 89 @property(nonatomic, retain) UIImage* favicon; | 92 @property(nonatomic, strong) UIImage* favicon; |
| 90 @property(nonatomic, retain) CloseButton* closeButton; | 93 @property(nonatomic, strong) CloseButton* closeButton; |
| 91 @property(nonatomic, retain) TitleLabel* titleLabel; | 94 @property(nonatomic, strong) TitleLabel* titleLabel; |
| 92 @property(nonatomic, assign) BOOL isIncognito; | 95 @property(nonatomic, assign) BOOL isIncognito; |
| 93 | 96 |
| 94 // Layout helper selectors that calculate the frames for subviews given the | 97 // Layout helper selectors that calculate the frames for subviews given the |
| 95 // bounds of the card tab. Note that the frames returned by these selectors | 98 // bounds of the card tab. Note that the frames returned by these selectors |
| 96 // will be different depending on the value of the |displaySide| property. | 99 // will be different depending on the value of the |displaySide| property. |
| 97 - (LayoutRect)faviconLayoutForBounds:(CGRect)bounds; | 100 - (LayoutRect)faviconLayoutForBounds:(CGRect)bounds; |
| 98 - (CGRect)faviconFrameForBounds:(CGRect)bounds; | 101 - (CGRect)faviconFrameForBounds:(CGRect)bounds; |
| 99 - (LayoutRect)titleLabelLayoutForBounds:(CGRect)bounds; | 102 - (LayoutRect)titleLabelLayoutForBounds:(CGRect)bounds; |
| 100 - (CGRect)titleLabelFrameForBounds:(CGRect)bounds; | 103 - (CGRect)titleLabelFrameForBounds:(CGRect)bounds; |
| 101 - (LayoutRect)closeButtonLayoutForBounds:(CGRect)bounds; | 104 - (LayoutRect)closeButtonLayoutForBounds:(CGRect)bounds; |
| (...skipping 15 matching lines...) Expand all Loading... |
| 117 - (void)cleanUpAnimations; | 120 - (void)cleanUpAnimations; |
| 118 | 121 |
| 119 // Initialize a CardTabView with |frame| and |isIncognito| state. | 122 // Initialize a CardTabView with |frame| and |isIncognito| state. |
| 120 - (instancetype)initWithFrame:(CGRect)frame | 123 - (instancetype)initWithFrame:(CGRect)frame |
| 121 isIncognito:(BOOL)isIncognito NS_DESIGNATED_INITIALIZER; | 124 isIncognito:(BOOL)isIncognito NS_DESIGNATED_INITIALIZER; |
| 122 | 125 |
| 123 - (instancetype)initWithCoder:(NSCoder*)aDecoder NS_UNAVAILABLE; | 126 - (instancetype)initWithCoder:(NSCoder*)aDecoder NS_UNAVAILABLE; |
| 124 | 127 |
| 125 @end | 128 @end |
| 126 | 129 |
| 127 @implementation CardTabView { | 130 @implementation CardTabView |
| 128 base::mac::ObjCPropertyReleaser _propertyReleaser_CardTabView; | |
| 129 } | |
| 130 | 131 |
| 131 #pragma mark - Property Implementation | 132 #pragma mark - Property Implementation |
| 132 | 133 |
| 133 @synthesize closeButtonSide = _closeButtonSide; | 134 @synthesize closeButtonSide = _closeButtonSide; |
| 134 @synthesize favIconView = _faviconView; | 135 @synthesize favIconView = _faviconView; |
| 135 @synthesize favicon = _favicon; | 136 @synthesize favicon = _favicon; |
| 136 @synthesize closeButton = _closeButton; | 137 @synthesize closeButton = _closeButton; |
| 137 @synthesize titleLabel = _titleLabel; | 138 @synthesize titleLabel = _titleLabel; |
| 138 @synthesize isIncognito = _isIncognito; | 139 @synthesize isIncognito = _isIncognito; |
| 139 | 140 |
| 140 - (instancetype)initWithFrame:(CGRect)frame { | 141 - (instancetype)initWithFrame:(CGRect)frame { |
| 141 return [self initWithFrame:frame isIncognito:NO]; | 142 return [self initWithFrame:frame isIncognito:NO]; |
| 142 } | 143 } |
| 143 | 144 |
| 144 - (instancetype)initWithFrame:(CGRect)frame isIncognito:(BOOL)isIncognito { | 145 - (instancetype)initWithFrame:(CGRect)frame isIncognito:(BOOL)isIncognito { |
| 145 self = [super initWithFrame:frame]; | 146 self = [super initWithFrame:frame]; |
| 146 if (!self) | 147 if (!self) |
| 147 return self; | 148 return self; |
| 148 | 149 |
| 149 _propertyReleaser_CardTabView.Init(self, [CardTabView class]); | |
| 150 _isIncognito = isIncognito; | 150 _isIncognito = isIncognito; |
| 151 | 151 |
| 152 UIImage* image = ImageWithName(@"default_favicon", _isIncognito); | 152 UIImage* image = ImageWithName(@"default_favicon", _isIncognito); |
| 153 _faviconView = [[UIImageView alloc] initWithImage:image]; | 153 _faviconView = [[UIImageView alloc] initWithImage:image]; |
| 154 [self addSubview:_faviconView]; | 154 [self addSubview:_faviconView]; |
| 155 | 155 |
| 156 UIImage* normal = ImageWithName(@"card_close_button", _isIncognito); | 156 UIImage* normal = ImageWithName(@"card_close_button", _isIncognito); |
| 157 UIImage* pressed = ImageWithName(@"card_close_button_pressed", _isIncognito); | 157 UIImage* pressed = ImageWithName(@"card_close_button_pressed", _isIncognito); |
| 158 | 158 |
| 159 _closeButton = [[CloseButton alloc] initWithFrame:CGRectZero]; | 159 _closeButton = [[CloseButton alloc] initWithFrame:CGRectZero]; |
| (...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 265 | 265 |
| 266 - (void)setTitle:(NSString*)title { | 266 - (void)setTitle:(NSString*)title { |
| 267 [_titleLabel setText:title]; | 267 [_titleLabel setText:title]; |
| 268 [_closeButton setAccessibilityValue:title]; | 268 [_closeButton setAccessibilityValue:title]; |
| 269 | 269 |
| 270 [self setNeedsUpdateConstraints]; | 270 [self setNeedsUpdateConstraints]; |
| 271 } | 271 } |
| 272 | 272 |
| 273 - (void)setFavicon:(UIImage*)favicon { | 273 - (void)setFavicon:(UIImage*)favicon { |
| 274 if (favicon != _favicon) { | 274 if (favicon != _favicon) { |
| 275 [favicon retain]; | |
| 276 [_favicon release]; | |
| 277 _favicon = favicon; | 275 _favicon = favicon; |
| 278 [self updateFaviconImage]; | 276 [self updateFaviconImage]; |
| 279 } | 277 } |
| 280 } | 278 } |
| 281 | 279 |
| 282 - (void)updateTitleColors { | 280 - (void)updateTitleColors { |
| 283 UIColor* titleColor = [UIColor blackColor]; | 281 UIColor* titleColor = [UIColor blackColor]; |
| 284 if (_isIncognito) | 282 if (_isIncognito) |
| 285 titleColor = [UIColor whiteColor]; | 283 titleColor = [UIColor whiteColor]; |
| 286 | 284 |
| (...skipping 143 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 430 else if (element == _titleLabel) | 428 else if (element == _titleLabel) |
| 431 index = closeButtonLeading ? 1 : 0; | 429 index = closeButtonLeading ? 1 : 0; |
| 432 return index; | 430 return index; |
| 433 } | 431 } |
| 434 | 432 |
| 435 @end | 433 @end |
| 436 | 434 |
| 437 #pragma mark - | 435 #pragma mark - |
| 438 | 436 |
| 439 @interface CardView () { | 437 @interface CardView () { |
| 440 base::scoped_nsobject<UIImageView> _contents; | 438 UIImageView* _contents; |
| 441 base::scoped_nsobject<CardTabView> _tab; | 439 CardTabView* _tab; |
| 442 id _cardCloseTarget; // weak | 440 __weak id _cardCloseTarget; |
| 443 SEL _cardCloseAction; | 441 SEL _cardCloseAction; |
| 444 id _accessibilityTarget; // weak | 442 __weak id _accessibilityTarget; |
| 445 SEL _accessibilityAction; | 443 SEL _accessibilityAction; |
| 446 | 444 |
| 447 BOOL _isIncognito; // YES if the card should use the incognito styling. | 445 BOOL _isIncognito; // YES if the card should use the incognito styling. |
| 448 | 446 |
| 449 // Pieces of the card frame, split into four UIViews. | 447 // Pieces of the card frame, split into four UIViews. |
| 450 base::scoped_nsobject<UIImageView> _frameLeft; | 448 UIImageView* _frameLeft; |
| 451 base::scoped_nsobject<UIImageView> _frameRight; | 449 UIImageView* _frameRight; |
| 452 base::scoped_nsobject<UIImageView> _frameTop; | 450 UIImageView* _frameTop; |
| 453 base::scoped_nsobject<UIImageView> _frameBottom; | 451 UIImageView* _frameBottom; |
| 454 base::scoped_nsobject<UIImageView> _frameShadowImageView; | 452 UIImageView* _frameShadowImageView; |
| 455 base::scoped_nsobject<CALayer> _shadowMask; | 453 CALayer* _shadowMask; |
| 456 } | 454 } |
| 457 | 455 |
| 458 // The LayoutRect for the CardTabView. | 456 // The LayoutRect for the CardTabView. |
| 459 - (LayoutRect)tabLayout; | 457 - (LayoutRect)tabLayout; |
| 460 | 458 |
| 461 // Sends |_cardCloseAction| to |_cardCloseTarget| with |self| as the sender. | 459 // Sends |_cardCloseAction| to |_cardCloseTarget| with |self| as the sender. |
| 462 - (void)closeButtonWasTapped:(id)sender; | 460 - (void)closeButtonWasTapped:(id)sender; |
| 463 | 461 |
| 464 // Resizes/zooms the snapshot to avoid stretching given the card's current | 462 // Resizes/zooms the snapshot to avoid stretching given the card's current |
| 465 // bounds. | 463 // bounds. |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 504 if (!self) | 502 if (!self) |
| 505 return self; | 503 return self; |
| 506 | 504 |
| 507 _isIncognito = isIncognito; | 505 _isIncognito = isIncognito; |
| 508 CGRect bounds = self.bounds; | 506 CGRect bounds = self.bounds; |
| 509 | 507 |
| 510 self.opaque = NO; | 508 self.opaque = NO; |
| 511 self.contentMode = UIViewContentModeRedraw; | 509 self.contentMode = UIViewContentModeRedraw; |
| 512 | 510 |
| 513 CGRect shadowFrame = UIEdgeInsetsInsetRect(bounds, kCardShadowLayoutOutsets); | 511 CGRect shadowFrame = UIEdgeInsetsInsetRect(bounds, kCardShadowLayoutOutsets); |
| 514 _frameShadowImageView.reset([[UIImageView alloc] initWithFrame:shadowFrame]); | 512 _frameShadowImageView = [[UIImageView alloc] initWithFrame:shadowFrame]; |
| 515 [_frameShadowImageView | 513 [_frameShadowImageView |
| 516 setAutoresizingMask:(UIViewAutoresizingFlexibleWidth | | 514 setAutoresizingMask:(UIViewAutoresizingFlexibleWidth | |
| 517 UIViewAutoresizingFlexibleHeight)]; | 515 UIViewAutoresizingFlexibleHeight)]; |
| 518 [self addSubview:_frameShadowImageView]; | 516 [self addSubview:_frameShadowImageView]; |
| 519 | 517 |
| 520 // Calling properties for side-effects. | 518 // Calling properties for side-effects. |
| 521 self.shouldShowShadow = YES; | 519 self.shouldShowShadow = YES; |
| 522 self.shouldMaskShadow = YES; | 520 self.shouldMaskShadow = YES; |
| 523 | 521 |
| 524 UIImage* image = [UIImage imageNamed:kCardShadowImageName]; | 522 UIImage* image = [UIImage imageNamed:kCardShadowImageName]; |
| 525 image = [image resizableImageWithCapInsets:kShadowStretchInsets]; | 523 image = [image resizableImageWithCapInsets:kShadowStretchInsets]; |
| 526 [_frameShadowImageView setImage:image]; | 524 [_frameShadowImageView setImage:image]; |
| 527 | 525 |
| 528 CGRect snapshotFrame = UIEdgeInsetsInsetRect(bounds, kCardImageInsets); | 526 CGRect snapshotFrame = UIEdgeInsetsInsetRect(bounds, kCardImageInsets); |
| 529 _contents.reset([[UIImageView alloc] initWithFrame:snapshotFrame]); | 527 _contents = [[UIImageView alloc] initWithFrame:snapshotFrame]; |
| 530 [_contents setClipsToBounds:YES]; | 528 [_contents setClipsToBounds:YES]; |
| 531 [_contents setContentMode:UIViewContentModeScaleAspectFill]; | 529 [_contents setContentMode:UIViewContentModeScaleAspectFill]; |
| 532 [_contents setFrame:snapshotFrame]; | 530 [_contents setFrame:snapshotFrame]; |
| 533 [_contents setAutoresizingMask:UIViewAutoresizingFlexibleWidth | | 531 [_contents setAutoresizingMask:UIViewAutoresizingFlexibleWidth | |
| 534 UIViewAutoresizingFlexibleHeight]; | 532 UIViewAutoresizingFlexibleHeight]; |
| 535 [self addSubview:_contents]; | 533 [self addSubview:_contents]; |
| 536 | 534 |
| 537 image = [UIImage imageNamed:isIncognito ? @"border_frame_incognito_left" | 535 image = [UIImage imageNamed:isIncognito ? @"border_frame_incognito_left" |
| 538 : @"border_frame_left"]; | 536 : @"border_frame_left"]; |
| 539 UIEdgeInsets imageStretchInsets = UIEdgeInsetsMake( | 537 UIEdgeInsets imageStretchInsets = UIEdgeInsetsMake( |
| 540 0.5 * image.size.height, 0.0, 0.5 * image.size.height, 0.0); | 538 0.5 * image.size.height, 0.0, 0.5 * image.size.height, 0.0); |
| 541 image = [image resizableImageWithCapInsets:imageStretchInsets]; | 539 image = [image resizableImageWithCapInsets:imageStretchInsets]; |
| 542 _frameLeft.reset([[UIImageView alloc] initWithImage:image]); | 540 _frameLeft = [[UIImageView alloc] initWithImage:image]; |
| 543 [self addSubview:_frameLeft]; | 541 [self addSubview:_frameLeft]; |
| 544 | 542 |
| 545 image = [UIImage imageNamed:isIncognito ? @"border_frame_incognito_right" | 543 image = [UIImage imageNamed:isIncognito ? @"border_frame_incognito_right" |
| 546 : @"border_frame_right"]; | 544 : @"border_frame_right"]; |
| 547 imageStretchInsets = UIEdgeInsetsMake(0.5 * image.size.height, 0.0, | 545 imageStretchInsets = UIEdgeInsetsMake(0.5 * image.size.height, 0.0, |
| 548 0.5 * image.size.height, 0.0); | 546 0.5 * image.size.height, 0.0); |
| 549 image = [image resizableImageWithCapInsets:imageStretchInsets]; | 547 image = [image resizableImageWithCapInsets:imageStretchInsets]; |
| 550 _frameRight.reset([[UIImageView alloc] initWithImage:image]); | 548 _frameRight = [[UIImageView alloc] initWithImage:image]; |
| 551 [self addSubview:_frameRight]; | 549 [self addSubview:_frameRight]; |
| 552 | 550 |
| 553 image = [UIImage imageNamed:isIncognito ? @"border_frame_incognito_top" | 551 image = [UIImage imageNamed:isIncognito ? @"border_frame_incognito_top" |
| 554 : @"border_frame_top"]; | 552 : @"border_frame_top"]; |
| 555 imageStretchInsets = UIEdgeInsetsMake(0.0, 0.5 * image.size.width, 0.0, | 553 imageStretchInsets = UIEdgeInsetsMake(0.0, 0.5 * image.size.width, 0.0, |
| 556 0.5 * image.size.width); | 554 0.5 * image.size.width); |
| 557 image = [image resizableImageWithCapInsets:imageStretchInsets]; | 555 image = [image resizableImageWithCapInsets:imageStretchInsets]; |
| 558 _frameTop.reset([[UIImageView alloc] initWithImage:image]); | 556 _frameTop = [[UIImageView alloc] initWithImage:image]; |
| 559 [self addSubview:_frameTop]; | 557 [self addSubview:_frameTop]; |
| 560 | 558 |
| 561 image = [UIImage imageNamed:isIncognito ? @"border_frame_incognito_bottom" | 559 image = [UIImage imageNamed:isIncognito ? @"border_frame_incognito_bottom" |
| 562 : @"border_frame_bottom"]; | 560 : @"border_frame_bottom"]; |
| 563 imageStretchInsets = UIEdgeInsetsMake(0.0, 0.5 * image.size.width, 0.0, | 561 imageStretchInsets = UIEdgeInsetsMake(0.0, 0.5 * image.size.width, 0.0, |
| 564 0.5 * image.size.width); | 562 0.5 * image.size.width); |
| 565 image = [image resizableImageWithCapInsets:imageStretchInsets]; | 563 image = [image resizableImageWithCapInsets:imageStretchInsets]; |
| 566 _frameBottom.reset([[UIImageView alloc] initWithImage:image]); | 564 _frameBottom = [[UIImageView alloc] initWithImage:image]; |
| 567 [self addSubview:_frameBottom]; | 565 [self addSubview:_frameBottom]; |
| 568 | 566 |
| 569 _tab.reset([[CardTabView alloc] | 567 _tab = [[CardTabView alloc] initWithFrame:LayoutRectGetRect([self tabLayout]) |
| 570 initWithFrame:LayoutRectGetRect([self tabLayout]) | 568 isIncognito:_isIncognito]; |
| 571 isIncognito:_isIncognito]); | |
| 572 [_tab setCloseButtonSide:IsPortrait() ? CardCloseButtonSide::TRAILING | 569 [_tab setCloseButtonSide:IsPortrait() ? CardCloseButtonSide::TRAILING |
| 573 : CardCloseButtonSide::LEADING]; | 570 : CardCloseButtonSide::LEADING]; |
| 574 [[_tab closeButton] addTarget:self | 571 [[_tab closeButton] addTarget:self |
| 575 action:@selector(closeButtonWasTapped:) | 572 action:@selector(closeButtonWasTapped:) |
| 576 forControlEvents:UIControlEventTouchUpInside]; | 573 forControlEvents:UIControlEventTouchUpInside]; |
| 577 [[_tab closeButton] | 574 [[_tab closeButton] |
| 578 addAccessibilityElementFocusedTarget:self | 575 addAccessibilityElementFocusedTarget:self |
| 579 action:@selector(elementDidBecomeFocused:)]; | 576 action:@selector(elementDidBecomeFocused:)]; |
| 580 [_tab closeButton].accessibilityIdentifier = [self closeButtonId]; | 577 [_tab closeButton].accessibilityIdentifier = [self closeButtonId]; |
| 581 | 578 |
| (...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 640 | 637 |
| 641 - (TitleLabel*)titleLabel { | 638 - (TitleLabel*)titleLabel { |
| 642 return [_tab titleLabel]; | 639 return [_tab titleLabel]; |
| 643 } | 640 } |
| 644 | 641 |
| 645 - (void)setFavicon:(UIImage*)favicon { | 642 - (void)setFavicon:(UIImage*)favicon { |
| 646 [_tab setFavicon:favicon]; | 643 [_tab setFavicon:favicon]; |
| 647 } | 644 } |
| 648 | 645 |
| 649 - (void)closeButtonWasTapped:(id)sender { | 646 - (void)closeButtonWasTapped:(id)sender { |
| 647 #pragma clang diagnostic push |
| 648 #pragma clang diagnostic ignored "-Warc-performSelector-leaks" |
| 650 [_cardCloseTarget performSelector:_cardCloseAction withObject:self]; | 649 [_cardCloseTarget performSelector:_cardCloseAction withObject:self]; |
| 650 #pragma clang diagnostic pop |
| 651 // Disable the tab's close button to prevent touch handling from the button | 651 // Disable the tab's close button to prevent touch handling from the button |
| 652 // while it's animating closed. | 652 // while it's animating closed. |
| 653 [_tab closeButton].enabled = NO; | 653 [_tab closeButton].enabled = NO; |
| 654 } | 654 } |
| 655 | 655 |
| 656 - (void)addCardCloseTarget:(id)target action:(SEL)action { | 656 - (void)addCardCloseTarget:(id)target action:(SEL)action { |
| 657 DCHECK(!target || [target respondsToSelector:action]); | 657 DCHECK(!target || [target respondsToSelector:action]); |
| 658 _cardCloseTarget = target; | 658 _cardCloseTarget = target; |
| 659 _cardCloseAction = action; | 659 _cardCloseAction = action; |
| 660 } | 660 } |
| (...skipping 11 matching lines...) Expand all Loading... |
| 672 CGRect cardBounds = {CGPointZero, cardSize}; | 672 CGRect cardBounds = {CGPointZero, cardSize}; |
| 673 CGSize viewSize = UIEdgeInsetsInsetRect(cardBounds, kCardImageInsets).size; | 673 CGSize viewSize = UIEdgeInsetsInsetRect(cardBounds, kCardImageInsets).size; |
| 674 CGSize imageSize = [_contents image].size; | 674 CGSize imageSize = [_contents image].size; |
| 675 CGFloat zoomRatio = std::max(viewSize.height / imageSize.height, | 675 CGFloat zoomRatio = std::max(viewSize.height / imageSize.height, |
| 676 viewSize.width / imageSize.width); | 676 viewSize.width / imageSize.width); |
| 677 return CGRectMake(0.0, 0.0, viewSize.width / (zoomRatio * imageSize.width), | 677 return CGRectMake(0.0, 0.0, viewSize.width / (zoomRatio * imageSize.width), |
| 678 viewSize.height / (zoomRatio * imageSize.height)); | 678 viewSize.height / (zoomRatio * imageSize.height)); |
| 679 } | 679 } |
| 680 | 680 |
| 681 - (void)updateImageBoundsAndZoom { | 681 - (void)updateImageBoundsAndZoom { |
| 682 UIImageView* imageView = _contents.get(); | 682 UIImageView* imageView = _contents; |
| 683 DCHECK(!CGRectEqualToRect(self.bounds, CGRectZero)); | 683 DCHECK(!CGRectEqualToRect(self.bounds, CGRectZero)); |
| 684 | 684 |
| 685 imageView.frame = UIEdgeInsetsInsetRect(self.bounds, kCardImageInsets); | 685 imageView.frame = UIEdgeInsetsInsetRect(self.bounds, kCardImageInsets); |
| 686 if (imageView.image) { | 686 if (imageView.image) { |
| 687 // Zoom the image to fill the available space. | 687 // Zoom the image to fill the available space. |
| 688 imageView.layer.contentsRect = | 688 imageView.layer.contentsRect = |
| 689 [self imageContentsRectForCardSize:self.bounds.size]; | 689 [self imageContentsRectForCardSize:self.bounds.size]; |
| 690 } | 690 } |
| 691 } | 691 } |
| 692 | 692 |
| 693 - (void)updateSnapshotAnimations { | 693 - (void)updateSnapshotAnimations { |
| 694 CAAnimation* snapshotAnimation = | 694 CAAnimation* snapshotAnimation = |
| 695 [[_contents layer] animationForKey:kCardViewAnimationKey]; | 695 [[_contents layer] animationForKey:kCardViewAnimationKey]; |
| 696 if (!snapshotAnimation) | 696 if (!snapshotAnimation) |
| 697 return; | 697 return; |
| 698 | 698 |
| 699 // Create copy of animation (animations become immutable after they're added | 699 // Create copy of animation (animations become immutable after they're added |
| 700 // to the layer). | 700 // to the layer). |
| 701 base::scoped_nsobject<CAAnimationGroup> updatedAnimation( | 701 CAAnimationGroup* updatedAnimation = [snapshotAnimation copy]; |
| 702 static_cast<CAAnimationGroup*>([snapshotAnimation copy])); | |
| 703 // Extract begin and end sizes of the card. | 702 // Extract begin and end sizes of the card. |
| 704 CAAnimation* cardAnimation = | 703 CAAnimation* cardAnimation = |
| 705 [self.layer animationForKey:kCardViewAnimationKey]; | 704 [self.layer animationForKey:kCardViewAnimationKey]; |
| 706 CABasicAnimation* cardBoundsAnimation = | 705 CABasicAnimation* cardBoundsAnimation = |
| 707 FindAnimationForKeyPath(@"bounds", cardAnimation); | 706 FindAnimationForKeyPath(@"bounds", cardAnimation); |
| 708 CGSize beginCardSize = [cardBoundsAnimation.fromValue CGRectValue].size; | 707 CGSize beginCardSize = [cardBoundsAnimation.fromValue CGRectValue].size; |
| 709 CGSize endCardSize = [cardBoundsAnimation.toValue CGRectValue].size; | 708 CGSize endCardSize = [cardBoundsAnimation.toValue CGRectValue].size; |
| 710 // Update the contentsRect animation. | 709 // Update the contentsRect animation. |
| 711 CABasicAnimation* contentsRectAnimation = | 710 CABasicAnimation* contentsRectAnimation = |
| 712 FindAnimationForKeyPath(@"contentsRect", updatedAnimation); | 711 FindAnimationForKeyPath(@"contentsRect", updatedAnimation); |
| (...skipping 26 matching lines...) Expand all Loading... |
| 739 } | 738 } |
| 740 return LayoutRectGetRect(maskLayout); | 739 return LayoutRectGetRect(maskLayout); |
| 741 } | 740 } |
| 742 | 741 |
| 743 - (void)updateShadowMask { | 742 - (void)updateShadowMask { |
| 744 if (!self.shouldShowShadow) | 743 if (!self.shouldShowShadow) |
| 745 return; | 744 return; |
| 746 | 745 |
| 747 if (self.shouldMaskShadow) { | 746 if (self.shouldMaskShadow) { |
| 748 if (!_shadowMask) { | 747 if (!_shadowMask) { |
| 749 _shadowMask.reset([[CALayer alloc] init]); | 748 _shadowMask = [[CALayer alloc] init]; |
| 750 [_shadowMask setBackgroundColor:[UIColor blackColor].CGColor]; | 749 [_shadowMask setBackgroundColor:[UIColor blackColor].CGColor]; |
| 751 } | 750 } |
| 752 [_frameShadowImageView layer].mask = _shadowMask; | 751 [_frameShadowImageView layer].mask = _shadowMask; |
| 753 [_shadowMask setFrame:[self shadowMaskFrameForBounds:self.bounds]]; | 752 [_shadowMask setFrame:[self shadowMaskFrameForBounds:self.bounds]]; |
| 754 } else { | 753 } else { |
| 755 [_frameShadowImageView layer].mask = nil; | 754 [_frameShadowImageView layer].mask = nil; |
| 756 } | 755 } |
| 757 } | 756 } |
| 758 | 757 |
| 759 - (LayoutRect)tabLayout { | 758 - (LayoutRect)tabLayout { |
| (...skipping 185 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 945 frameAnimation = FrameAnimationMake( | 944 frameAnimation = FrameAnimationMake( |
| 946 [_frameShadowImageView layer], | 945 [_frameShadowImageView layer], |
| 947 UIEdgeInsetsInsetRect(beginBounds, kCardShadowLayoutOutsets), | 946 UIEdgeInsetsInsetRect(beginBounds, kCardShadowLayoutOutsets), |
| 948 UIEdgeInsetsInsetRect(endBounds, kCardShadowLayoutOutsets)); | 947 UIEdgeInsetsInsetRect(endBounds, kCardShadowLayoutOutsets)); |
| 949 frameAnimation.duration = frameDuration; | 948 frameAnimation.duration = frameDuration; |
| 950 frameAnimation.timingFunction = frameTiming; | 949 frameAnimation.timingFunction = frameTiming; |
| 951 [[_frameShadowImageView layer] addAnimation:frameAnimation | 950 [[_frameShadowImageView layer] addAnimation:frameAnimation |
| 952 forKey:kCardViewAnimationKey]; | 951 forKey:kCardViewAnimationKey]; |
| 953 if (self.shouldMaskShadow) { | 952 if (self.shouldMaskShadow) { |
| 954 frameAnimation = FrameAnimationMake( | 953 frameAnimation = FrameAnimationMake( |
| 955 _shadowMask.get(), [self shadowMaskFrameForBounds:beginBounds], | 954 _shadowMask, [self shadowMaskFrameForBounds:beginBounds], |
| 956 [self shadowMaskFrameForBounds:endBounds]); | 955 [self shadowMaskFrameForBounds:endBounds]); |
| 957 frameAnimation.duration = frameDuration; | 956 frameAnimation.duration = frameDuration; |
| 958 frameAnimation.timingFunction = frameTiming; | 957 frameAnimation.timingFunction = frameTiming; |
| 959 [_shadowMask addAnimation:frameAnimation forKey:kCardViewAnimationKey]; | 958 [_shadowMask addAnimation:frameAnimation forKey:kCardViewAnimationKey]; |
| 960 } | 959 } |
| 961 } | 960 } |
| 962 | 961 |
| 963 // Update content snapshot | 962 // Update content snapshot |
| 964 CGRect beginContentFrame = | 963 CGRect beginContentFrame = |
| 965 UIEdgeInsetsInsetRect(beginBounds, kCardImageInsets); | 964 UIEdgeInsetsInsetRect(beginBounds, kCardImageInsets); |
| (...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1022 [_tab titleLabel]); | 1021 [_tab titleLabel]); |
| 1023 } | 1022 } |
| 1024 | 1023 |
| 1025 - (void)addAccessibilityTarget:(id)target action:(SEL)action { | 1024 - (void)addAccessibilityTarget:(id)target action:(SEL)action { |
| 1026 DCHECK(!target || [target respondsToSelector:action]); | 1025 DCHECK(!target || [target respondsToSelector:action]); |
| 1027 _accessibilityTarget = target; | 1026 _accessibilityTarget = target; |
| 1028 _accessibilityAction = action; | 1027 _accessibilityAction = action; |
| 1029 } | 1028 } |
| 1030 | 1029 |
| 1031 - (void)elementDidBecomeFocused:(id)sender { | 1030 - (void)elementDidBecomeFocused:(id)sender { |
| 1031 #pragma clang diagnostic push |
| 1032 #pragma clang diagnostic ignored "-Warc-performSelector-leaks" |
| 1032 [_accessibilityTarget performSelector:_accessibilityAction withObject:sender]; | 1033 [_accessibilityTarget performSelector:_accessibilityAction withObject:sender]; |
| 1034 #pragma clang diagnostic pop |
| 1033 } | 1035 } |
| 1034 | 1036 |
| 1035 @end | 1037 @end |
| OLD | NEW |