OLD | NEW |
| (Empty) |
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 | |
3 // found in the LICENSE file. | |
4 | |
5 #include "ash/app_list/app_list_bubble_border.h" | |
6 | |
7 #include "third_party/skia/include/core/SkPath.h" | |
8 #include "third_party/skia/include/core/SkPaint.h" | |
9 #include "third_party/skia/include/effects/SkBlurDrawLooper.h" | |
10 #include "third_party/skia/include/effects/SkGradientShader.h" | |
11 #include "ui/gfx/canvas.h" | |
12 | |
13 namespace { | |
14 | |
15 const int kCornerRadius = 3; | |
16 | |
17 const int kArrowHeight = 10; | |
18 const int kArrowWidth = 20; | |
19 | |
20 const SkColor kBorderColor = SkColorSetARGB(0xFF, 0, 0, 0); | |
21 const int kBorderSize = 1; | |
22 | |
23 const SkColor kShadowColor = SkColorSetARGB(0xFF, 0, 0, 0); | |
24 const int kShadowRadius = 4; | |
25 | |
26 const SkColor kModelViewGradientColor1 = SkColorSetARGB(0xFF, 0xFE, 0xFE, 0xFE); | |
27 const SkColor kModelViewGradientColor2 = SkColorSetARGB(0xFF, 0xF8, 0xF8, 0xF8); | |
28 const int kModelViewGradientSize = 10; | |
29 | |
30 const SkColor kFooterBorderGradientColor1 = | |
31 SkColorSetARGB(0xFF, 0xA0, 0xA0, 0xA0); | |
32 const SkColor kFooterBorderGradientColor2 = | |
33 SkColorSetARGB(0xFF, 0xD4, 0xD4, 0xD4); | |
34 const int kFooterBorderSize = 3; | |
35 const SkColor kFooterBackground = SkColorSetARGB(0xFF, 0xDC, 0xDC, 0xDC); | |
36 | |
37 // TODO(xiyuan): Merge this with the one in skia_util. | |
38 SkShader* CreateVerticalGradientShader(int start_point, | |
39 int end_point, | |
40 SkColor start_color, | |
41 SkColor end_color, | |
42 SkShader::TileMode mode) { | |
43 SkColor grad_colors[2] = { start_color, end_color}; | |
44 SkPoint grad_points[2]; | |
45 grad_points[0].iset(0, start_point); | |
46 grad_points[1].iset(0, end_point); | |
47 | |
48 return SkGradientShader::CreateLinear(grad_points, | |
49 grad_colors, | |
50 NULL, | |
51 2, | |
52 mode); | |
53 } | |
54 | |
55 // Builds a bubble shape for given |bounds|. | |
56 void BuildShape(const gfx::Rect& bounds, | |
57 SkScalar padding, | |
58 SkScalar arrow_offset, | |
59 SkPath* path) { | |
60 const SkScalar left = SkIntToScalar(bounds.x()) + padding; | |
61 const SkScalar top = SkIntToScalar(bounds.y()) + padding; | |
62 const SkScalar right = SkIntToScalar(bounds.right()) - padding; | |
63 const SkScalar bottom = SkIntToScalar(bounds.bottom()) - padding; | |
64 | |
65 const SkScalar center_x = SkIntToScalar((bounds.x() + bounds.right()) / 2); | |
66 const SkScalar center_y = SkIntToScalar((bounds.y() + bounds.bottom()) / 2); | |
67 | |
68 const SkScalar half_array_width = SkIntToScalar(kArrowWidth / 2); | |
69 const SkScalar arrow_height = SkIntToScalar(kArrowHeight) - padding; | |
70 | |
71 path->reset(); | |
72 path->incReserve(12); | |
73 | |
74 path->moveTo(center_x, top); | |
75 path->arcTo(left, top, left, center_y, SkIntToScalar(kCornerRadius)); | |
76 path->arcTo(left, bottom, center_x - half_array_width, bottom, | |
77 SkIntToScalar(kCornerRadius)); | |
78 path->lineTo(center_x + arrow_offset - half_array_width, bottom); | |
79 path->lineTo(center_x + arrow_offset, bottom + arrow_height); | |
80 path->lineTo(center_x + arrow_offset + half_array_width, bottom); | |
81 path->arcTo(right, bottom, right, center_y, SkIntToScalar(kCornerRadius)); | |
82 path->arcTo(right, top, center_x, top, SkIntToScalar(kCornerRadius)); | |
83 path->close(); | |
84 } | |
85 | |
86 } // namespace | |
87 | |
88 namespace ash { | |
89 | |
90 AppListBubbleBorder::AppListBubbleBorder(views::View* app_list_view) | |
91 : views::BubbleBorder(views::BubbleBorder::BOTTOM_RIGHT, | |
92 views::BubbleBorder::NO_SHADOW), | |
93 app_list_view_(app_list_view), | |
94 arrow_offset_(0) { | |
95 } | |
96 | |
97 AppListBubbleBorder::~AppListBubbleBorder() { | |
98 } | |
99 | |
100 void AppListBubbleBorder::PaintModelViewBackground( | |
101 gfx::Canvas* canvas, | |
102 const gfx::Rect& bounds) const { | |
103 const views::View* page_switcher = app_list_view_->child_at(1); | |
104 const gfx::Rect page_switcher_bounds = | |
105 app_list_view_->ConvertRectToWidget(page_switcher->bounds()); | |
106 gfx::Rect rect(bounds.x(), | |
107 bounds.y(), | |
108 bounds.width(), | |
109 page_switcher_bounds.y() - bounds.y()); | |
110 | |
111 SkPaint paint; | |
112 paint.setStyle(SkPaint::kFill_Style); | |
113 SkSafeUnref(paint.setShader(CreateVerticalGradientShader( | |
114 rect.y(), | |
115 rect.y() + kModelViewGradientSize, | |
116 kModelViewGradientColor1, | |
117 kModelViewGradientColor2, | |
118 SkShader::kClamp_TileMode))); | |
119 canvas->DrawRect(rect, paint); | |
120 } | |
121 | |
122 void AppListBubbleBorder::PaintPageSwitcherBackground( | |
123 gfx::Canvas* canvas, | |
124 const gfx::Rect& bounds) const { | |
125 const views::View* page_switcher = app_list_view_->child_at(1); | |
126 const gfx::Rect page_switcher_bounds = | |
127 app_list_view_->ConvertRectToWidget(page_switcher->bounds()); | |
128 | |
129 gfx::Rect rect(bounds.x(), | |
130 page_switcher_bounds.y(), | |
131 bounds.width(), | |
132 kFooterBorderSize); | |
133 SkPaint paint; | |
134 paint.setStyle(SkPaint::kFill_Style); | |
135 SkSafeUnref(paint.setShader(CreateVerticalGradientShader( | |
136 rect.y(), | |
137 rect.bottom(), | |
138 kFooterBorderGradientColor1, | |
139 kFooterBorderGradientColor2, | |
140 SkShader::kClamp_TileMode))); | |
141 canvas->DrawRect(rect, paint); | |
142 | |
143 rect.set_y(rect.bottom()); | |
144 rect.set_height(bounds.bottom() - rect.y() + kArrowHeight - kBorderSize); | |
145 canvas->FillRect(rect, kFooterBackground); | |
146 } | |
147 | |
148 void AppListBubbleBorder::GetInsets(gfx::Insets* insets) const { | |
149 insets->Set(kShadowRadius + kBorderSize, | |
150 kShadowRadius + kBorderSize, | |
151 kShadowRadius + kBorderSize + kArrowHeight, | |
152 kShadowRadius + kBorderSize); | |
153 } | |
154 | |
155 gfx::Rect AppListBubbleBorder::GetBounds( | |
156 const gfx::Rect& position_relative_to, | |
157 const gfx::Size& contents_size) const { | |
158 gfx::Size border_size(contents_size); | |
159 gfx::Insets insets; | |
160 GetInsets(&insets); | |
161 border_size.Enlarge(insets.width(), insets.height()); | |
162 | |
163 int anchor_x = (position_relative_to.x() + position_relative_to.right()) / 2; | |
164 int arrow_tip_x = border_size.width() / 2 + arrow_offset_; | |
165 | |
166 return gfx::Rect( | |
167 gfx::Point(anchor_x - arrow_tip_x, | |
168 position_relative_to.y() - border_size.height() + | |
169 kShadowRadius), | |
170 border_size); | |
171 } | |
172 | |
173 void AppListBubbleBorder::Paint(const views::View& view, | |
174 gfx::Canvas* canvas) const { | |
175 gfx::Insets insets; | |
176 GetInsets(&insets); | |
177 | |
178 gfx::Rect bounds = view.bounds(); | |
179 bounds.Inset(insets); | |
180 | |
181 SkPath path; | |
182 | |
183 SkPaint paint; | |
184 paint.setAntiAlias(true); | |
185 paint.setStyle(SkPaint::kStroke_Style); | |
186 paint.setColor(kBorderColor); | |
187 SkSafeUnref(paint.setLooper( | |
188 new SkBlurDrawLooper(kShadowRadius, | |
189 0, 0, | |
190 kShadowColor, | |
191 SkBlurDrawLooper::kHighQuality_BlurFlag))); | |
192 // Pads with 0.5 pixel since anti alias is used. | |
193 BuildShape(bounds, | |
194 SkDoubleToScalar(0.5), | |
195 SkIntToScalar(arrow_offset_), | |
196 &path); | |
197 canvas->DrawPath(path, paint); | |
198 | |
199 // Pads with kBoprderSize pixels to leave space for border lines. | |
200 BuildShape(bounds, | |
201 SkIntToScalar(kBorderSize), | |
202 SkIntToScalar(arrow_offset_), | |
203 &path); | |
204 canvas->Save(); | |
205 canvas->ClipPath(path); | |
206 | |
207 PaintModelViewBackground(canvas, bounds); | |
208 PaintPageSwitcherBackground(canvas, bounds); | |
209 | |
210 canvas->Restore(); | |
211 } | |
212 | |
213 } // namespace ash | |
OLD | NEW |