| 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 |