Mattias Nissler | b1fdeb5a | 2015-07-09 12:10:39 | [diff] [blame] | 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 |
| 3 | // found in the LICENSE file. |
| 4 | |
| 5 | #include "ui/gfx/paint_vector_icon.h" |
| 6 | |
estade | 2ee31b3 | 2015-07-29 16:49:54 | [diff] [blame] | 7 | #include <map> |
jsbell | 7faa086 | 2015-11-20 01:26:56 | [diff] [blame^] | 8 | #include <tuple> |
estade | 2ee31b3 | 2015-07-29 16:49:54 | [diff] [blame] | 9 | |
| 10 | #include "base/lazy_instance.h" |
estade | 6c87460 | 2015-08-04 22:45:24 | [diff] [blame] | 11 | #include "base/strings/string_number_conversions.h" |
| 12 | #include "base/strings/string_split.h" |
estade | 7ca51e2 | 2015-08-31 19:03:33 | [diff] [blame] | 13 | #include "third_party/skia/include/core/SkPaint.h" |
bungeman | ac16189 | 2015-08-03 19:40:31 | [diff] [blame] | 14 | #include "third_party/skia/include/core/SkPath.h" |
estade | 7ca51e2 | 2015-08-31 19:03:33 | [diff] [blame] | 15 | #include "third_party/skia/include/core/SkXfermode.h" |
Mattias Nissler | b1fdeb5a | 2015-07-09 12:10:39 | [diff] [blame] | 16 | #include "ui/gfx/canvas.h" |
estade | a204e0c | 2015-07-22 19:54:31 | [diff] [blame] | 17 | #include "ui/gfx/image/canvas_image_source.h" |
estade | 0a679f8 | 2015-07-16 19:31:56 | [diff] [blame] | 18 | #include "ui/gfx/vector_icon_types.h" |
estade | 73e2dc1 | 2015-08-31 22:43:31 | [diff] [blame] | 19 | #include "ui/gfx/vector_icons.h" |
Mattias Nissler | b1fdeb5a | 2015-07-09 12:10:39 | [diff] [blame] | 20 | |
| 21 | namespace gfx { |
| 22 | |
estade | a204e0c | 2015-07-22 19:54:31 | [diff] [blame] | 23 | namespace { |
| 24 | |
estade | 6c87460 | 2015-08-04 22:45:24 | [diff] [blame] | 25 | // Translates a string such as "MOVE_TO" into a command such as MOVE_TO. |
| 26 | CommandType CommandFromString(const std::string& source) { |
| 27 | #define RETURN_IF_IS(command) \ |
| 28 | if (source == #command) \ |
| 29 | return command; |
estade | a204e0c | 2015-07-22 19:54:31 | [diff] [blame] | 30 | |
estade | dbdbdfe | 2015-08-05 23:05:07 | [diff] [blame] | 31 | RETURN_IF_IS(NEW_PATH); |
| 32 | RETURN_IF_IS(PATH_COLOR_ARGB); |
estade | 7ca51e2 | 2015-08-31 19:03:33 | [diff] [blame] | 33 | RETURN_IF_IS(PATH_MODE_CLEAR); |
Evan Stade | cedd7da7 | 2015-08-06 22:58:43 | [diff] [blame] | 34 | RETURN_IF_IS(STROKE); |
estade | ab97e1d | 2015-09-21 22:42:22 | [diff] [blame] | 35 | RETURN_IF_IS(CAP_SQUARE); |
estade | 6c87460 | 2015-08-04 22:45:24 | [diff] [blame] | 36 | RETURN_IF_IS(MOVE_TO); |
| 37 | RETURN_IF_IS(R_MOVE_TO); |
estade | dbdbdfe | 2015-08-05 23:05:07 | [diff] [blame] | 38 | RETURN_IF_IS(LINE_TO); |
estade | 6c87460 | 2015-08-04 22:45:24 | [diff] [blame] | 39 | RETURN_IF_IS(R_LINE_TO); |
| 40 | RETURN_IF_IS(H_LINE_TO); |
| 41 | RETURN_IF_IS(R_H_LINE_TO); |
| 42 | RETURN_IF_IS(V_LINE_TO); |
| 43 | RETURN_IF_IS(R_V_LINE_TO); |
| 44 | RETURN_IF_IS(CUBIC_TO); |
| 45 | RETURN_IF_IS(R_CUBIC_TO); |
| 46 | RETURN_IF_IS(CIRCLE); |
estade | 490f73b | 2015-09-25 01:40:49 | [diff] [blame] | 47 | RETURN_IF_IS(ROUND_RECT); |
estade | 6c87460 | 2015-08-04 22:45:24 | [diff] [blame] | 48 | RETURN_IF_IS(CLOSE); |
estade | dbdbdfe | 2015-08-05 23:05:07 | [diff] [blame] | 49 | RETURN_IF_IS(CANVAS_DIMENSIONS); |
Evan Stade | cedd7da7 | 2015-08-06 22:58:43 | [diff] [blame] | 50 | RETURN_IF_IS(CLIP); |
estade | 20db97e7 | 2015-08-13 17:46:58 | [diff] [blame] | 51 | RETURN_IF_IS(DISABLE_AA); |
estade | 6c87460 | 2015-08-04 22:45:24 | [diff] [blame] | 52 | RETURN_IF_IS(END); |
| 53 | #undef RETURN_IF_IS |
estade | a204e0c | 2015-07-22 19:54:31 | [diff] [blame] | 54 | |
estade | 6c87460 | 2015-08-04 22:45:24 | [diff] [blame] | 55 | NOTREACHED(); |
| 56 | return CLOSE; |
| 57 | } |
| 58 | |
| 59 | std::vector<PathElement> PathFromSource(const std::string& source) { |
| 60 | std::vector<PathElement> path; |
| 61 | std::vector<std::string> pieces = base::SplitString( |
| 62 | source, "\n ,f", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY); |
| 63 | for (const auto& piece : pieces) { |
| 64 | double value; |
| 65 | if (base::StringToDouble(piece, &value)) |
| 66 | path.push_back(PathElement(SkDoubleToScalar(value))); |
| 67 | else |
| 68 | path.push_back(PathElement(CommandFromString(piece))); |
estade | a204e0c | 2015-07-22 19:54:31 | [diff] [blame] | 69 | } |
estade | 6c87460 | 2015-08-04 22:45:24 | [diff] [blame] | 70 | return path; |
| 71 | } |
estade | a204e0c | 2015-07-22 19:54:31 | [diff] [blame] | 72 | |
estade | 6c87460 | 2015-08-04 22:45:24 | [diff] [blame] | 73 | void PaintPath(Canvas* canvas, |
| 74 | const PathElement* path_elements, |
| 75 | size_t dip_size, |
| 76 | SkColor color) { |
estade | 7ca51e2 | 2015-08-31 19:03:33 | [diff] [blame] | 77 | canvas->Save(); |
estade | 6c87460 | 2015-08-04 22:45:24 | [diff] [blame] | 78 | SkPath path; |
| 79 | path.setFillType(SkPath::kEvenOdd_FillType); |
estade | 804d247 | 2015-08-03 18:54:34 | [diff] [blame] | 80 | |
estade | 804d247 | 2015-08-03 18:54:34 | [diff] [blame] | 81 | size_t canvas_size = kReferenceSizeDip; |
estade | 20db97e7 | 2015-08-13 17:46:58 | [diff] [blame] | 82 | std::vector<SkPath> paths; |
estade | dbdbdfe | 2015-08-05 23:05:07 | [diff] [blame] | 83 | std::vector<SkPaint> paints; |
Evan Stade | cedd7da7 | 2015-08-06 22:58:43 | [diff] [blame] | 84 | SkRect clip_rect = SkRect::MakeEmpty(); |
| 85 | |
estade | eaac88b | 2015-07-30 17:29:39 | [diff] [blame] | 86 | for (size_t i = 0; path_elements[i].type != END; i++) { |
estade | 20db97e7 | 2015-08-13 17:46:58 | [diff] [blame] | 87 | if (paths.empty() || path_elements[i].type == NEW_PATH) { |
| 88 | paths.push_back(SkPath()); |
| 89 | paths.back().setFillType(SkPath::kEvenOdd_FillType); |
| 90 | |
| 91 | paints.push_back(SkPaint()); |
| 92 | paints.back().setColor(color); |
| 93 | paints.back().setAntiAlias(true); |
| 94 | paints.back().setStrokeCap(SkPaint::kRound_Cap); |
| 95 | } |
| 96 | |
estade | 804d247 | 2015-08-03 18:54:34 | [diff] [blame] | 97 | SkPath& path = paths.back(); |
Evan Stade | cedd7da7 | 2015-08-06 22:58:43 | [diff] [blame] | 98 | SkPaint& paint = paints.back(); |
estade | eaac88b | 2015-07-30 17:29:39 | [diff] [blame] | 99 | switch (path_elements[i].type) { |
estade | 20db97e7 | 2015-08-13 17:46:58 | [diff] [blame] | 100 | // Handled above. |
| 101 | case NEW_PATH: |
| 102 | continue; |
estade | dbdbdfe | 2015-08-05 23:05:07 | [diff] [blame] | 103 | |
| 104 | case PATH_COLOR_ARGB: { |
| 105 | int a = SkScalarFloorToInt(path_elements[++i].arg); |
| 106 | int r = SkScalarFloorToInt(path_elements[++i].arg); |
| 107 | int g = SkScalarFloorToInt(path_elements[++i].arg); |
| 108 | int b = SkScalarFloorToInt(path_elements[++i].arg); |
Evan Stade | cedd7da7 | 2015-08-06 22:58:43 | [diff] [blame] | 109 | paint.setColor(SkColorSetARGB(a, r, g, b)); |
| 110 | break; |
| 111 | } |
| 112 | |
estade | 7ca51e2 | 2015-08-31 19:03:33 | [diff] [blame] | 113 | case PATH_MODE_CLEAR: { |
| 114 | paint.setXfermodeMode(SkXfermode::kClear_Mode); |
| 115 | break; |
| 116 | }; |
| 117 | |
Evan Stade | cedd7da7 | 2015-08-06 22:58:43 | [diff] [blame] | 118 | case STROKE: { |
| 119 | paint.setStyle(SkPaint::kStroke_Style); |
| 120 | SkScalar width = path_elements[++i].arg; |
| 121 | paint.setStrokeWidth(width); |
estade | 804d247 | 2015-08-03 18:54:34 | [diff] [blame] | 122 | break; |
| 123 | } |
| 124 | |
estade | ab97e1d | 2015-09-21 22:42:22 | [diff] [blame] | 125 | case CAP_SQUARE: { |
| 126 | paint.setStrokeCap(SkPaint::kSquare_Cap); |
| 127 | break; |
| 128 | } |
| 129 | |
Mattias Nissler | b1fdeb5a | 2015-07-09 12:10:39 | [diff] [blame] | 130 | case MOVE_TO: { |
estade | eaac88b | 2015-07-30 17:29:39 | [diff] [blame] | 131 | SkScalar x = path_elements[++i].arg; |
| 132 | SkScalar y = path_elements[++i].arg; |
Mattias Nissler | b1fdeb5a | 2015-07-09 12:10:39 | [diff] [blame] | 133 | path.moveTo(x, y); |
| 134 | break; |
| 135 | } |
| 136 | |
| 137 | case R_MOVE_TO: { |
estade | eaac88b | 2015-07-30 17:29:39 | [diff] [blame] | 138 | SkScalar x = path_elements[++i].arg; |
| 139 | SkScalar y = path_elements[++i].arg; |
Mattias Nissler | b1fdeb5a | 2015-07-09 12:10:39 | [diff] [blame] | 140 | path.rMoveTo(x, y); |
| 141 | break; |
| 142 | } |
| 143 | |
| 144 | case LINE_TO: { |
estade | eaac88b | 2015-07-30 17:29:39 | [diff] [blame] | 145 | SkScalar x = path_elements[++i].arg; |
| 146 | SkScalar y = path_elements[++i].arg; |
Mattias Nissler | b1fdeb5a | 2015-07-09 12:10:39 | [diff] [blame] | 147 | path.lineTo(x, y); |
| 148 | break; |
| 149 | } |
| 150 | |
| 151 | case R_LINE_TO: { |
estade | eaac88b | 2015-07-30 17:29:39 | [diff] [blame] | 152 | SkScalar x = path_elements[++i].arg; |
| 153 | SkScalar y = path_elements[++i].arg; |
Mattias Nissler | b1fdeb5a | 2015-07-09 12:10:39 | [diff] [blame] | 154 | path.rLineTo(x, y); |
| 155 | break; |
| 156 | } |
| 157 | |
| 158 | case H_LINE_TO: { |
| 159 | SkPoint last_point; |
| 160 | path.getLastPt(&last_point); |
estade | eaac88b | 2015-07-30 17:29:39 | [diff] [blame] | 161 | SkScalar x = path_elements[++i].arg; |
Mattias Nissler | b1fdeb5a | 2015-07-09 12:10:39 | [diff] [blame] | 162 | path.lineTo(x, last_point.fY); |
| 163 | break; |
| 164 | } |
| 165 | |
| 166 | case R_H_LINE_TO: { |
estade | eaac88b | 2015-07-30 17:29:39 | [diff] [blame] | 167 | SkScalar x = path_elements[++i].arg; |
Mattias Nissler | b1fdeb5a | 2015-07-09 12:10:39 | [diff] [blame] | 168 | path.rLineTo(x, 0); |
| 169 | break; |
| 170 | } |
| 171 | |
| 172 | case V_LINE_TO: { |
| 173 | SkPoint last_point; |
| 174 | path.getLastPt(&last_point); |
estade | eaac88b | 2015-07-30 17:29:39 | [diff] [blame] | 175 | SkScalar y = path_elements[++i].arg; |
Mattias Nissler | b1fdeb5a | 2015-07-09 12:10:39 | [diff] [blame] | 176 | path.lineTo(last_point.fX, y); |
| 177 | break; |
| 178 | } |
| 179 | |
| 180 | case R_V_LINE_TO: { |
estade | eaac88b | 2015-07-30 17:29:39 | [diff] [blame] | 181 | SkScalar y = path_elements[++i].arg; |
Mattias Nissler | b1fdeb5a | 2015-07-09 12:10:39 | [diff] [blame] | 182 | path.rLineTo(0, y); |
| 183 | break; |
| 184 | } |
| 185 | |
estade | e141609 | 2015-07-29 18:24:12 | [diff] [blame] | 186 | case CUBIC_TO: { |
estade | eaac88b | 2015-07-30 17:29:39 | [diff] [blame] | 187 | SkScalar x1 = path_elements[++i].arg; |
| 188 | SkScalar y1 = path_elements[++i].arg; |
| 189 | SkScalar x2 = path_elements[++i].arg; |
| 190 | SkScalar y2 = path_elements[++i].arg; |
| 191 | SkScalar x3 = path_elements[++i].arg; |
| 192 | SkScalar y3 = path_elements[++i].arg; |
estade | e141609 | 2015-07-29 18:24:12 | [diff] [blame] | 193 | path.cubicTo(x1, y1, x2, y2, x3, y3); |
| 194 | break; |
| 195 | } |
| 196 | |
Mattias Nissler | b1fdeb5a | 2015-07-09 12:10:39 | [diff] [blame] | 197 | case R_CUBIC_TO: { |
estade | eaac88b | 2015-07-30 17:29:39 | [diff] [blame] | 198 | SkScalar x1 = path_elements[++i].arg; |
| 199 | SkScalar y1 = path_elements[++i].arg; |
| 200 | SkScalar x2 = path_elements[++i].arg; |
| 201 | SkScalar y2 = path_elements[++i].arg; |
| 202 | SkScalar x3 = path_elements[++i].arg; |
| 203 | SkScalar y3 = path_elements[++i].arg; |
Mattias Nissler | b1fdeb5a | 2015-07-09 12:10:39 | [diff] [blame] | 204 | path.rCubicTo(x1, y1, x2, y2, x3, y3); |
| 205 | break; |
| 206 | } |
| 207 | |
estade | eaac88b | 2015-07-30 17:29:39 | [diff] [blame] | 208 | case CIRCLE: { |
| 209 | SkScalar x = path_elements[++i].arg; |
| 210 | SkScalar y = path_elements[++i].arg; |
| 211 | SkScalar r = path_elements[++i].arg; |
| 212 | path.addCircle(x, y, r); |
| 213 | break; |
| 214 | } |
| 215 | |
estade | 490f73b | 2015-09-25 01:40:49 | [diff] [blame] | 216 | case ROUND_RECT: { |
| 217 | SkScalar x = path_elements[++i].arg; |
| 218 | SkScalar y = path_elements[++i].arg; |
| 219 | SkScalar w = path_elements[++i].arg; |
| 220 | SkScalar h = path_elements[++i].arg; |
| 221 | SkScalar radius = path_elements[++i].arg; |
| 222 | path.addRoundRect(SkRect::MakeXYWH(x, y, w, h), radius, radius); |
| 223 | break; |
| 224 | } |
| 225 | |
Mattias Nissler | b1fdeb5a | 2015-07-09 12:10:39 | [diff] [blame] | 226 | case CLOSE: { |
| 227 | path.close(); |
| 228 | break; |
| 229 | } |
| 230 | |
estade | 804d247 | 2015-08-03 18:54:34 | [diff] [blame] | 231 | case CANVAS_DIMENSIONS: { |
| 232 | SkScalar width = path_elements[++i].arg; |
| 233 | canvas_size = SkScalarTruncToInt(width); |
| 234 | break; |
| 235 | } |
| 236 | |
Evan Stade | cedd7da7 | 2015-08-06 22:58:43 | [diff] [blame] | 237 | case CLIP: { |
| 238 | SkScalar x = path_elements[++i].arg; |
| 239 | SkScalar y = path_elements[++i].arg; |
| 240 | SkScalar w = path_elements[++i].arg; |
| 241 | SkScalar h = path_elements[++i].arg; |
| 242 | clip_rect = SkRect::MakeXYWH(x, y, w, h); |
| 243 | break; |
| 244 | } |
| 245 | |
estade | 20db97e7 | 2015-08-13 17:46:58 | [diff] [blame] | 246 | case DISABLE_AA: { |
| 247 | paint.setAntiAlias(false); |
| 248 | break; |
| 249 | } |
| 250 | |
Mattias Nissler | b1fdeb5a | 2015-07-09 12:10:39 | [diff] [blame] | 251 | case END: |
| 252 | NOTREACHED(); |
| 253 | break; |
| 254 | } |
| 255 | } |
| 256 | |
estade | 804d247 | 2015-08-03 18:54:34 | [diff] [blame] | 257 | if (dip_size != canvas_size) { |
| 258 | SkScalar scale = SkIntToScalar(dip_size) / SkIntToScalar(canvas_size); |
| 259 | canvas->sk_canvas()->scale(scale, scale); |
| 260 | } |
| 261 | |
Evan Stade | cedd7da7 | 2015-08-06 22:58:43 | [diff] [blame] | 262 | if (!clip_rect.isEmpty()) |
| 263 | canvas->sk_canvas()->clipRect(clip_rect); |
| 264 | |
estade | dbdbdfe | 2015-08-05 23:05:07 | [diff] [blame] | 265 | DCHECK_EQ(paints.size(), paths.size()); |
estade | 20db97e7 | 2015-08-13 17:46:58 | [diff] [blame] | 266 | for (size_t i = 0; i < paths.size(); ++i) |
estade | dbdbdfe | 2015-08-05 23:05:07 | [diff] [blame] | 267 | canvas->DrawPath(paths[i], paints[i]); |
estade | 7ca51e2 | 2015-08-31 19:03:33 | [diff] [blame] | 268 | canvas->Restore(); |
Mattias Nissler | b1fdeb5a | 2015-07-09 12:10:39 | [diff] [blame] | 269 | } |
| 270 | |
estade | 6c87460 | 2015-08-04 22:45:24 | [diff] [blame] | 271 | class VectorIconSource : public CanvasImageSource { |
| 272 | public: |
estade | 7ca51e2 | 2015-08-31 19:03:33 | [diff] [blame] | 273 | VectorIconSource(VectorIconId id, |
| 274 | size_t dip_size, |
| 275 | SkColor color, |
| 276 | VectorIconId badge_id) |
estade | 6c87460 | 2015-08-04 22:45:24 | [diff] [blame] | 277 | : CanvasImageSource( |
| 278 | gfx::Size(static_cast<int>(dip_size), static_cast<int>(dip_size)), |
| 279 | false), |
| 280 | id_(id), |
estade | 7ca51e2 | 2015-08-31 19:03:33 | [diff] [blame] | 281 | color_(color), |
| 282 | badge_id_(badge_id) {} |
estade | 6c87460 | 2015-08-04 22:45:24 | [diff] [blame] | 283 | |
| 284 | VectorIconSource(const std::string& definition, |
| 285 | size_t dip_size, |
| 286 | SkColor color) |
| 287 | : CanvasImageSource( |
| 288 | gfx::Size(static_cast<int>(dip_size), static_cast<int>(dip_size)), |
| 289 | false), |
| 290 | id_(VectorIconId::VECTOR_ICON_NONE), |
| 291 | path_(PathFromSource(definition)), |
estade | 7ca51e2 | 2015-08-31 19:03:33 | [diff] [blame] | 292 | color_(color), |
| 293 | badge_id_(VectorIconId::VECTOR_ICON_NONE) {} |
estade | 6c87460 | 2015-08-04 22:45:24 | [diff] [blame] | 294 | |
| 295 | ~VectorIconSource() override {} |
| 296 | |
| 297 | // CanvasImageSource: |
| 298 | void Draw(gfx::Canvas* canvas) override { |
estade | 7ca51e2 | 2015-08-31 19:03:33 | [diff] [blame] | 299 | if (path_.empty()) { |
estade | 6c87460 | 2015-08-04 22:45:24 | [diff] [blame] | 300 | PaintVectorIcon(canvas, id_, size_.width(), color_); |
estade | 7ca51e2 | 2015-08-31 19:03:33 | [diff] [blame] | 301 | if (badge_id_ != VectorIconId::VECTOR_ICON_NONE) |
| 302 | PaintVectorIcon(canvas, badge_id_, size_.width(), color_); |
| 303 | } else { |
estade | 6c87460 | 2015-08-04 22:45:24 | [diff] [blame] | 304 | PaintPath(canvas, path_.data(), size_.width(), color_); |
estade | 7ca51e2 | 2015-08-31 19:03:33 | [diff] [blame] | 305 | } |
estade | 6c87460 | 2015-08-04 22:45:24 | [diff] [blame] | 306 | } |
| 307 | |
| 308 | private: |
| 309 | const VectorIconId id_; |
| 310 | const std::vector<PathElement> path_; |
| 311 | const SkColor color_; |
estade | 7ca51e2 | 2015-08-31 19:03:33 | [diff] [blame] | 312 | const VectorIconId badge_id_; |
estade | 6c87460 | 2015-08-04 22:45:24 | [diff] [blame] | 313 | |
| 314 | DISALLOW_COPY_AND_ASSIGN(VectorIconSource); |
| 315 | }; |
| 316 | |
| 317 | // This class caches vector icons (as ImageSkia) so they don't have to be drawn |
| 318 | // more than once. This also guarantees the backing data for the images returned |
| 319 | // by CreateVectorIcon will persist in memory until program termination. |
| 320 | class VectorIconCache { |
| 321 | public: |
| 322 | VectorIconCache() {} |
| 323 | ~VectorIconCache() {} |
| 324 | |
estade | 7ca51e2 | 2015-08-31 19:03:33 | [diff] [blame] | 325 | ImageSkia GetOrCreateIcon(VectorIconId id, |
| 326 | size_t dip_size, |
| 327 | SkColor color, |
| 328 | VectorIconId badge_id) { |
| 329 | IconDescription description(id, dip_size, color, badge_id); |
estade | 6c87460 | 2015-08-04 22:45:24 | [diff] [blame] | 330 | auto iter = images_.find(description); |
| 331 | if (iter != images_.end()) |
| 332 | return iter->second; |
| 333 | |
| 334 | ImageSkia icon( |
estade | 7ca51e2 | 2015-08-31 19:03:33 | [diff] [blame] | 335 | new VectorIconSource(id, dip_size, color, badge_id), |
estade | 6c87460 | 2015-08-04 22:45:24 | [diff] [blame] | 336 | gfx::Size(static_cast<int>(dip_size), static_cast<int>(dip_size))); |
| 337 | images_.insert(std::make_pair(description, icon)); |
| 338 | return icon; |
| 339 | } |
| 340 | |
| 341 | private: |
| 342 | struct IconDescription { |
estade | 7ca51e2 | 2015-08-31 19:03:33 | [diff] [blame] | 343 | IconDescription(VectorIconId id, |
| 344 | size_t dip_size, |
| 345 | SkColor color, |
| 346 | VectorIconId badge_id) |
| 347 | : id(id), dip_size(dip_size), color(color), badge_id(badge_id) {} |
estade | 6c87460 | 2015-08-04 22:45:24 | [diff] [blame] | 348 | |
| 349 | bool operator<(const IconDescription& other) const { |
jsbell | 7faa086 | 2015-11-20 01:26:56 | [diff] [blame^] | 350 | return std::tie(id, dip_size, color, badge_id) < |
| 351 | std::tie(other.id, other.dip_size, other.color, other.badge_id); |
estade | 6c87460 | 2015-08-04 22:45:24 | [diff] [blame] | 352 | } |
| 353 | |
| 354 | VectorIconId id; |
| 355 | size_t dip_size; |
| 356 | SkColor color; |
estade | 7ca51e2 | 2015-08-31 19:03:33 | [diff] [blame] | 357 | VectorIconId badge_id; |
estade | 6c87460 | 2015-08-04 22:45:24 | [diff] [blame] | 358 | }; |
| 359 | |
| 360 | std::map<IconDescription, ImageSkia> images_; |
| 361 | |
| 362 | DISALLOW_COPY_AND_ASSIGN(VectorIconCache); |
| 363 | }; |
| 364 | |
| 365 | static base::LazyInstance<VectorIconCache> g_icon_cache = |
| 366 | LAZY_INSTANCE_INITIALIZER; |
| 367 | |
| 368 | } // namespace |
| 369 | |
| 370 | void PaintVectorIcon(Canvas* canvas, |
| 371 | VectorIconId id, |
| 372 | size_t dip_size, |
| 373 | SkColor color) { |
| 374 | DCHECK(VectorIconId::VECTOR_ICON_NONE != id); |
Evan Stade | cedd7da7 | 2015-08-06 22:58:43 | [diff] [blame] | 375 | const PathElement* path = canvas->image_scale() == 1.f |
| 376 | ? GetPathForVectorIconAt1xScale(id) |
| 377 | : GetPathForVectorIcon(id); |
| 378 | PaintPath(canvas, path, dip_size, color); |
estade | 6c87460 | 2015-08-04 22:45:24 | [diff] [blame] | 379 | } |
| 380 | |
estade | a204e0c | 2015-07-22 19:54:31 | [diff] [blame] | 381 | ImageSkia CreateVectorIcon(VectorIconId id, size_t dip_size, SkColor color) { |
estade | 7ca51e2 | 2015-08-31 19:03:33 | [diff] [blame] | 382 | return CreateVectorIconWithBadge(id, dip_size, color, |
| 383 | VectorIconId::VECTOR_ICON_NONE); |
| 384 | } |
| 385 | |
| 386 | ImageSkia CreateVectorIconWithBadge(VectorIconId id, |
| 387 | size_t dip_size, |
| 388 | SkColor color, |
| 389 | VectorIconId badge_id) { |
| 390 | return g_icon_cache.Get().GetOrCreateIcon(id, dip_size, color, badge_id); |
estade | a204e0c | 2015-07-22 19:54:31 | [diff] [blame] | 391 | } |
| 392 | |
estade | 6c87460 | 2015-08-04 22:45:24 | [diff] [blame] | 393 | ImageSkia CreateVectorIconFromSource(const std::string& source, |
| 394 | size_t dip_size, |
| 395 | SkColor color) { |
| 396 | return ImageSkia( |
| 397 | new VectorIconSource(source, dip_size, color), |
| 398 | gfx::Size(static_cast<int>(dip_size), static_cast<int>(dip_size))); |
| 399 | } |
| 400 | |
Mattias Nissler | b1fdeb5a | 2015-07-09 12:10:39 | [diff] [blame] | 401 | } // namespace gfx |