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