blob: 213a0f61b57c584144340b3813b20d4003125cbf [file] [log] [blame]
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#import "ios/chrome/browser/ui/omnibox/truncating_attributed_label.h"
#include <algorithm>
#include "base/mac/scoped_cftyperef.h"
#if !defined(__has_feature) || !__has_feature(objc_arc)
#error "This file requires ARC support."
#endif
@interface OmniboxPopupTruncatingLabel ()
- (void)setup;
- (UIImage*)getLinearGradient:(CGRect)rect;
@end
@implementation OmniboxPopupTruncatingLabel {
// Gradient used to create fade effect. Changes based on view.frame size.
UIImage* gradient_;
}
@synthesize truncateMode = truncateMode_;
- (void)setup {
self.backgroundColor = [UIColor clearColor];
truncateMode_ = OmniboxPopupTruncatingTail;
}
- (id)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
self.lineBreakMode = NSLineBreakByClipping;
[self setup];
}
return self;
}
- (void)awakeFromNib {
[super awakeFromNib];
[self setup];
}
- (void)setFrame:(CGRect)frame {
[super setFrame:frame];
// Cache the fade gradient when the frame changes.
if (!CGRectIsEmpty(frame) &&
(!gradient_ || !CGSizeEqualToSize([gradient_ size], frame.size))) {
CGRect rect = CGRectMake(0, 0, frame.size.width, frame.size.height);
gradient_ = [self getLinearGradient:rect];
}
}
// Draw fade gradient mask if attributedText is wider than rect.
- (void)drawTextInRect:(CGRect)requestedRect {
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSaveGState(context);
if ([self.attributedText size].width > requestedRect.size.width)
CGContextClipToMask(context, self.bounds, [gradient_ CGImage]);
// Add the specified line break and alignment attributes to attributedText and
// draw the result.
NSMutableAttributedString* attributedString =
[self.attributedText mutableCopy];
NSMutableParagraphStyle* textStyle =
[[NSParagraphStyle defaultParagraphStyle] mutableCopy];
textStyle.lineBreakMode = self.lineBreakMode;
textStyle.alignment = self.textAlignment;
[attributedString addAttribute:NSParagraphStyleAttributeName
value:textStyle
range:NSMakeRange(0, [self.text length])];
[attributedString drawInRect:requestedRect];
CGContextRestoreGState(context);
}
- (void)setTextAlignment:(NSTextAlignment)textAlignment {
if (textAlignment == NSTextAlignmentLeft) {
self.truncateMode = OmniboxPopupTruncatingTail;
} else if (textAlignment == NSTextAlignmentRight) {
self.truncateMode = OmniboxPopupTruncatingHead;
} else if (textAlignment == NSTextAlignmentNatural) {
self.truncateMode = OmniboxPopupTruncatingTail;
} else {
NOTREACHED();
}
if (textAlignment != self.textAlignment)
gradient_ = nil;
[super setTextAlignment:textAlignment];
}
// Create gradient opacity mask based on direction.
- (UIImage*)getLinearGradient:(CGRect)rect {
// Create an opaque context.
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceGray();
CGContextRef context =
CGBitmapContextCreate(NULL, rect.size.width, rect.size.height, 8,
4 * rect.size.width, colorSpace, kCGImageAlphaNone);
// White background will mask opaque, black gradient will mask transparent.
CGContextSetFillColorWithColor(context, [UIColor whiteColor].CGColor);
CGContextFillRect(context, rect);
// Create gradient from white to black.
CGFloat locs[2] = {0.0f, 1.0f};
CGFloat components[4] = {1.0f, 1.0f, 0.0f, 1.0f};
CGGradientRef gradient =
CGGradientCreateWithColorComponents(colorSpace, components, locs, 2);
CGColorSpaceRelease(colorSpace);
// Draw head and/or tail gradient.
CGFloat fadeWidth =
std::min(rect.size.height * 2, (CGFloat)floor(rect.size.width / 4));
CGFloat minX = CGRectGetMinX(rect);
CGFloat maxX = CGRectGetMaxX(rect);
if (self.truncateMode & OmniboxPopupTruncatingTail) {
CGFloat startX = maxX - fadeWidth;
CGPoint startPoint = CGPointMake(startX, CGRectGetMidY(rect));
CGPoint endPoint = CGPointMake(maxX, CGRectGetMidY(rect));
CGContextDrawLinearGradient(context, gradient, startPoint, endPoint, 0);
}
if (self.truncateMode & OmniboxPopupTruncatingHead) {
CGFloat startX = minX + fadeWidth;
CGPoint startPoint = CGPointMake(startX, CGRectGetMidY(rect));
CGPoint endPoint = CGPointMake(minX, CGRectGetMidY(rect));
CGContextDrawLinearGradient(context, gradient, startPoint, endPoint, 0);
}
CGGradientRelease(gradient);
// Clean up, return image.
CGImageRef ref = CGBitmapContextCreateImage(context);
UIImage* image = [UIImage imageWithCGImage:ref];
CGImageRelease(ref);
CGContextRelease(context);
return image;
}
@end