Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / ui / cocoa / styled_text_field_cell.mm
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #import "chrome/browser/ui/cocoa/styled_text_field_cell.h"
6
7 #include "base/logging.h"
8 #include "chrome/browser/themes/theme_properties.h"
9 #include "chrome/browser/themes/theme_service.h"
10 #import "chrome/browser/ui/cocoa/themed_window.h"
11 #include "grit/theme_resources.h"
12 #import "ui/base/cocoa/nsgraphics_context_additions.h"
13 #import "ui/base/cocoa/nsview_additions.h"
14 #include "ui/gfx/font.h"
15 #include "ui/gfx/scoped_ns_graphics_context_save_gstate_mac.h"
16
17 @implementation StyledTextFieldCell
18
19 - (CGFloat)topTextFrameOffset {
20   return 0.0;
21 }
22
23 - (CGFloat)bottomTextFrameOffset {
24   return 0.0;
25 }
26
27 - (CGFloat)cornerRadius {
28   return 0.0;
29 }
30
31 - (rect_path_utils::RoundedCornerFlags)roundedCornerFlags {
32   return rect_path_utils::RoundedCornerAll;
33 }
34
35 - (BOOL)shouldDrawBezel {
36   return NO;
37 }
38
39 - (NSRect)textFrameForFrameInternal:(NSRect)cellFrame {
40   CGFloat topOffset = [self topTextFrameOffset];
41   NSRect textFrame = cellFrame;
42   textFrame.origin.y += topOffset;
43   textFrame.size.height -= topOffset + [self bottomTextFrameOffset];
44   return textFrame;
45 }
46
47 // Returns the same value as textCursorFrameForFrame, but does not call it
48 // directly to avoid potential infinite loops.
49 - (NSRect)textFrameForFrame:(NSRect)cellFrame {
50   return [self textFrameForFrameInternal:cellFrame];
51 }
52
53 // Returns the same value as textFrameForFrame, but does not call it directly to
54 // avoid potential infinite loops.
55 - (NSRect)textCursorFrameForFrame:(NSRect)cellFrame {
56   return [self textFrameForFrameInternal:cellFrame];
57 }
58
59 // Override to show the I-beam cursor only in the area given by
60 // |textCursorFrameForFrame:|.
61 - (void)resetCursorRect:(NSRect)cellFrame inView:(NSView *)controlView {
62   [super resetCursorRect:[self textCursorFrameForFrame:cellFrame]
63                   inView:controlView];
64 }
65
66 // For NSTextFieldCell this is the area within the borders.  For our
67 // purposes, we count the info decorations as being part of the
68 // border.
69 - (NSRect)drawingRectForBounds:(NSRect)theRect {
70   return [super drawingRectForBounds:[self textFrameForFrame:theRect]];
71 }
72
73 // TODO(shess): This code is manually drawing the cell's border area,
74 // but otherwise the cell assumes -setBordered:YES for purposes of
75 // calculating things like the editing area.  This is probably
76 // incorrect.  I know that this affects -drawingRectForBounds:.
77 - (void)drawWithFrame:(NSRect)cellFrame inView:(NSView*)controlView {
78   const CGFloat lineWidth = [controlView cr_lineWidth];
79   const CGFloat halfLineWidth = lineWidth / 2.0;
80
81   DCHECK([controlView isFlipped]);
82   rect_path_utils::RoundedCornerFlags roundedCornerFlags =
83       [self roundedCornerFlags];
84
85   // TODO(shess): This inset is also reflected by |kFieldVisualInset|
86   // in omnibox_popup_view_mac.mm.
87   const NSRect frame = NSInsetRect(cellFrame, 0, lineWidth);
88   const CGFloat radius = [self cornerRadius];
89
90   // Paint button background image if there is one (otherwise the border won't
91   // look right).
92   ThemeService* themeProvider =
93       static_cast<ThemeService*>([[controlView window] themeProvider]);
94   if (themeProvider) {
95     NSColor* backgroundImageColor = nil;
96     if (themeProvider->HasCustomImage(IDR_THEME_BUTTON_BACKGROUND)) {
97       backgroundImageColor =
98           themeProvider->GetNSImageColorNamed(IDR_THEME_BUTTON_BACKGROUND);
99     }
100     if (backgroundImageColor) {
101       // Set the phase to match window.
102       NSRect trueRect = [controlView convertRect:cellFrame toView:nil];
103       NSPoint midPoint = NSMakePoint(NSMinX(trueRect), NSMaxY(trueRect));
104       [[NSGraphicsContext currentContext] cr_setPatternPhase:midPoint
105                                                      forView:controlView];
106
107       // NOTE(shess): This seems like it should be using a 0.0 inset,
108       // but AFAICT using a halfLineWidth inset is important in mixing the
109       // toolbar background and the omnibox background.
110       rect_path_utils::FillRectWithInset(roundedCornerFlags, frame,
111                                          halfLineWidth, halfLineWidth, radius,
112                                          backgroundImageColor);
113     }
114
115     // Draw the outer stroke (over the background).
116     BOOL active = [[controlView window] isMainWindow];
117     NSColor* strokeColor = themeProvider->GetNSColor(
118         active ? ThemeProperties::COLOR_TOOLBAR_BUTTON_STROKE :
119                  ThemeProperties::COLOR_TOOLBAR_BUTTON_STROKE_INACTIVE);
120     rect_path_utils::FrameRectWithInset(roundedCornerFlags, frame, 0.0, 0.0,
121                                         radius, lineWidth, strokeColor);
122   }
123
124   // Fill interior with background color.
125   rect_path_utils::FillRectWithInset(roundedCornerFlags, frame, lineWidth,
126                                      lineWidth, radius,
127                                      [self backgroundColor]);
128
129   // Draw the shadow.  For the rounded-rect case, the shadow needs to
130   // slightly turn in at the corners.  |shadowFrame| is at the same
131   // midline as the inner border line on the top and left, but at the
132   // outer border line on the bottom and right.  The clipping change
133   // will clip the bottom and right edges (and corner).
134   {
135     gfx::ScopedNSGraphicsContextSaveGState state;
136     [rect_path_utils::RectPathWithInset(roundedCornerFlags, frame, lineWidth,
137                                         lineWidth, radius) addClip];
138     const NSRect shadowFrame =
139         NSOffsetRect(frame, halfLineWidth, halfLineWidth);
140     NSColor* shadowShade = [NSColor colorWithCalibratedWhite:0.0
141                                                        alpha:0.05 / lineWidth];
142     rect_path_utils::FrameRectWithInset(roundedCornerFlags, shadowFrame,
143                                         halfLineWidth, halfLineWidth,
144                                         radius - halfLineWidth, lineWidth,
145                                         shadowShade);
146   }
147
148   // Draw optional bezel below bottom stroke.
149   if ([self shouldDrawBezel] && themeProvider &&
150       themeProvider->UsingDefaultTheme()) {
151
152     NSColor* bezelColor = themeProvider->GetNSColor(
153         ThemeProperties::COLOR_TOOLBAR_BEZEL);
154     [[bezelColor colorWithAlphaComponent:0.5 / lineWidth] set];
155     NSRect bezelRect = NSMakeRect(cellFrame.origin.x,
156                                   NSMaxY(cellFrame) - lineWidth,
157                                   NSWidth(cellFrame),
158                                   lineWidth);
159     bezelRect = NSInsetRect(bezelRect, radius - halfLineWidth, 0.0);
160     NSRectFillUsingOperation(bezelRect, NSCompositeSourceOver);
161   }
162
163   // Draw the interior before the focus ring, to make sure nothing overlaps it.
164   [self drawInteriorWithFrame:cellFrame inView:controlView];
165
166   // Draw the focus ring if needed.
167   if ([self showsFirstResponder]) {
168     NSColor* color = [[NSColor keyboardFocusIndicatorColor]
169         colorWithAlphaComponent:0.5 / lineWidth];
170     rect_path_utils::FrameRectWithInset(roundedCornerFlags, frame, 0.0, 0.0,
171                                         radius, lineWidth * 2, color);
172   }
173 }
174
175 @end