| OLD | NEW |
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 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 "ios/chrome/browser/ui/util/label_link_controller.h" | 5 #import "ios/chrome/browser/ui/util/label_link_controller.h" |
| 6 | 6 |
| 7 #include <map> | 7 #include <map> |
| 8 #include <vector> | 8 #include <vector> |
| 9 | 9 |
| 10 #include "base/ios/ios_util.h" | 10 #include "base/ios/ios_util.h" |
| (...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 126 // If there are tap buttons, but they are not subviews of |_label|'s superview | 126 // If there are tap buttons, but they are not subviews of |_label|'s superview |
| 127 // (if _label's superview has changed since the buttons were created), then | 127 // (if _label's superview has changed since the buttons were created), then |
| 128 // the tap buttons are migrated into the new superview. | 128 // the tap buttons are migrated into the new superview. |
| 129 - (void)updateTapButtons; | 129 - (void)updateTapButtons; |
| 130 | 130 |
| 131 @end | 131 @end |
| 132 | 132 |
| 133 @implementation LabelLinkController { | 133 @implementation LabelLinkController { |
| 134 // Ivars immutable for the lifetime of the object. | 134 // Ivars immutable for the lifetime of the object. |
| 135 base::mac::ScopedBlock<ProceduralBlockWithURL> _action; | 135 base::mac::ScopedBlock<ProceduralBlockWithURL> _action; |
| 136 base::WeakNSObject<UILabel> _label; // weak | 136 base::scoped_nsobject<UILabel> _label; |
| 137 base::scoped_nsobject<UITapGestureRecognizer> _linkTapRecognizer; | 137 base::scoped_nsobject<UITapGestureRecognizer> _linkTapRecognizer; |
| 138 | 138 |
| 139 // Ivas backing properties. | 139 // Ivas backing properties. |
| 140 base::scoped_nsobject<UIColor> _linkColor; | 140 base::scoped_nsobject<UIColor> _linkColor; |
| 141 base::scoped_nsobject<UIFont> _linkFont; | 141 base::scoped_nsobject<UIFont> _linkFont; |
| 142 | 142 |
| 143 // Ivars that reset when label text changes. | 143 // Ivars that reset when label text changes. |
| 144 base::scoped_nsobject<NSMutableDictionary> _layoutsForURLs; | 144 base::scoped_nsobject<NSMutableDictionary> _layoutsForURLs; |
| 145 base::scoped_nsobject<NSAttributedString> _originalLabelText; | 145 base::scoped_nsobject<NSAttributedString> _originalLabelText; |
| 146 CGRect _lastLabelFrame; | 146 CGRect _lastLabelFrame; |
| 147 | 147 |
| 148 // Ivars that reset when text or bounds change. | 148 // Ivars that reset when text or bounds change. |
| 149 base::scoped_nsprotocol<id<TextRegionMapper>> _textMapper; | 149 base::scoped_nsprotocol<id<TextRegionMapper>> _textMapper; |
| 150 | 150 |
| 151 // Internal tracking. | 151 // Internal tracking. |
| 152 BOOL _justUpdatedStyles; | 152 BOOL _justUpdatedStyles; |
| 153 base::scoped_nsobject<NSMutableArray> _linkButtons; | 153 base::scoped_nsobject<NSMutableArray> _linkButtons; |
| 154 base::scoped_nsobject<LabelObserver> _labelObserver; |
| 154 } | 155 } |
| 155 | 156 |
| 156 @synthesize showTapAreas = _showTapAreas; | 157 @synthesize showTapAreas = _showTapAreas; |
| 157 @synthesize textMapperClass = _textMapperClass; | 158 @synthesize textMapperClass = _textMapperClass; |
| 158 @synthesize linkUnderlineStyle = _linkUnderlineStyle; | 159 @synthesize linkUnderlineStyle = _linkUnderlineStyle; |
| 159 | 160 |
| 160 - (instancetype)initWithLabel:(UILabel*)label | 161 - (instancetype)initWithLabel:(UILabel*)label |
| 161 action:(ProceduralBlockWithURL)action { | 162 action:(ProceduralBlockWithURL)action { |
| 162 if ((self = [super init])) { | 163 if ((self = [super init])) { |
| 163 DCHECK(label); | 164 DCHECK(label); |
| 164 _label.reset(label); | 165 _label.reset([label retain]); |
| 165 _action.reset(action, base::scoped_policy::RETAIN); | 166 _action.reset(action, base::scoped_policy::RETAIN); |
| 166 _linkUnderlineStyle = NSUnderlineStyleNone; | 167 _linkUnderlineStyle = NSUnderlineStyleNone; |
| 167 [self reset]; | 168 [self reset]; |
| 168 | 169 |
| 170 _labelObserver.reset([[LabelObserver observerForLabel:_label] retain]); |
| 171 [_labelObserver startObserving]; |
| 169 [self addLabelObserverActions]; | 172 [self addLabelObserverActions]; |
| 170 | 173 |
| 171 self.textMapperClass = [CoreTextRegionMapper class]; | 174 self.textMapperClass = [CoreTextRegionMapper class]; |
| 172 _linkButtons.reset([[NSMutableArray alloc] init]); | 175 _linkButtons.reset([[NSMutableArray alloc] init]); |
| 173 } | 176 } |
| 174 return self; | 177 return self; |
| 175 } | 178 } |
| 176 | 179 |
| 177 - (NSAttributedString*)originalLabelText { | 180 - (NSAttributedString*)originalLabelText { |
| 178 return _originalLabelText.get(); | 181 return _originalLabelText.get(); |
| 179 } | 182 } |
| 180 | 183 |
| 181 - (NSArray*)linkButtons { | 184 - (NSArray*)linkButtons { |
| 182 return _linkButtons.get(); | 185 return _linkButtons.get(); |
| 183 } | 186 } |
| 184 | 187 |
| 185 - (void)addLabelObserverActions { | 188 - (void)addLabelObserverActions { |
| 186 LabelObserver* observer = [LabelObserver observerForLabel:_label]; | |
| 187 base::WeakNSObject<LabelLinkController> weakSelf(self); | 189 base::WeakNSObject<LabelLinkController> weakSelf(self); |
| 188 [observer addStyleChangedAction:^(UILabel* label) { | 190 [_labelObserver addStyleChangedAction:^(UILabel* label) { |
| 189 // One of the style properties has been changed, which will silently | 191 // One of the style properties has been changed, which will silently |
| 190 // update the label's attributedText. | 192 // update the label's attributedText. |
| 191 if (!weakSelf) | 193 if (!weakSelf) |
| 192 return; | 194 return; |
| 193 base::scoped_nsobject<LabelLinkController> strongSelf([weakSelf retain]); | 195 base::scoped_nsobject<LabelLinkController> strongSelf([weakSelf retain]); |
| 194 [strongSelf labelStyleInvalidated]; | 196 [strongSelf labelStyleInvalidated]; |
| 195 }]; | 197 }]; |
| 196 [observer addTextChangedAction:^(UILabel* label) { | 198 [_labelObserver addTextChangedAction:^(UILabel* label) { |
| 197 if (!weakSelf) | 199 if (!weakSelf) |
| 198 return; | 200 return; |
| 199 base::scoped_nsobject<LabelLinkController> strongSelf([weakSelf retain]); | 201 base::scoped_nsobject<LabelLinkController> strongSelf([weakSelf retain]); |
| 200 NSString* originalText = [[strongSelf originalLabelText] string]; | 202 NSString* originalText = [[strongSelf originalLabelText] string]; |
| 201 if ([label.text isEqualToString:originalText]) { | 203 if ([label.text isEqualToString:originalText]) { |
| 202 // The actual text of the label didn't change, so this was a change to | 204 // The actual text of the label didn't change, so this was a change to |
| 203 // the string attributes only. | 205 // the string attributes only. |
| 204 [strongSelf labelStyleInvalidated]; | 206 [strongSelf labelStyleInvalidated]; |
| 205 } else { | 207 } else { |
| 206 // The label text has changed, so start everything from scratch. | 208 // The label text has changed, so start everything from scratch. |
| 207 [strongSelf reset]; | 209 [strongSelf reset]; |
| 208 } | 210 } |
| 209 }]; | 211 }]; |
| 210 [observer addLayoutChangedAction:^(UILabel* label) { | 212 [_labelObserver addLayoutChangedAction:^(UILabel* label) { |
| 211 if (!weakSelf) | 213 if (!weakSelf) |
| 212 return; | 214 return; |
| 213 base::scoped_nsobject<LabelLinkController> strongSelf([weakSelf retain]); | 215 base::scoped_nsobject<LabelLinkController> strongSelf([weakSelf retain]); |
| 214 [strongSelf labelLayoutInvalidated]; | 216 [strongSelf labelLayoutInvalidated]; |
| 215 NSArray* linkButtons = [strongSelf linkButtons]; | 217 NSArray* linkButtons = [strongSelf linkButtons]; |
| 216 // If this layout change corresponds to |label|'s moving to a new superview, | 218 // If this layout change corresponds to |label|'s moving to a new superview, |
| 217 // update the tap buttons so that they are inserted above |label| in the new | 219 // update the tap buttons so that they are inserted above |label| in the new |
| 218 // hierarchy. | 220 // hierarchy. |
| 219 if (linkButtons.count && label.superview != [linkButtons[0] superview]) | 221 if (linkButtons.count && label.superview != [linkButtons[0] superview]) |
| 220 [strongSelf updateTapButtons]; | 222 [strongSelf updateTapButtons]; |
| 221 }]; | 223 }]; |
| 222 } | 224 } |
| 223 | 225 |
| 224 - (void)dealloc { | 226 - (void)dealloc { |
| 225 [self clearTapButtons]; | 227 [self clearTapButtons]; |
| 228 [_labelObserver stopObserving]; |
| 226 [super dealloc]; | 229 [super dealloc]; |
| 227 } | 230 } |
| 228 | 231 |
| 229 - (void)addLinkWithRange:(NSRange)range url:(GURL)url { | 232 - (void)addLinkWithRange:(NSRange)range url:(GURL)url { |
| 230 DCHECK(url.is_valid()); | 233 DCHECK(url.is_valid()); |
| 231 if (!_layoutsForURLs) | 234 if (!_layoutsForURLs) |
| 232 _layoutsForURLs.reset([[NSMutableDictionary alloc] init]); | 235 _layoutsForURLs.reset([[NSMutableDictionary alloc] init]); |
| 233 NSURL* key = net::NSURLWithGURL(url); | 236 NSURL* key = net::NSURLWithGURL(url); |
| 234 base::scoped_nsobject<LinkLayout> layout( | 237 base::scoped_nsobject<LinkLayout> layout( |
| 235 [[LinkLayout alloc] initWithRange:range]); | 238 [[LinkLayout alloc] initWithRange:range]); |
| (...skipping 206 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 442 if (CGRectContainsPoint(frame, point)) { | 445 if (CGRectContainsPoint(frame, point)) { |
| 443 _action.get()(net::GURLWithNSURL(key)); | 446 _action.get()(net::GURLWithNSURL(key)); |
| 444 *stop = YES; | 447 *stop = YES; |
| 445 break; | 448 break; |
| 446 } | 449 } |
| 447 } | 450 } |
| 448 }]; | 451 }]; |
| 449 } | 452 } |
| 450 | 453 |
| 451 @end | 454 @end |
| OLD | NEW |