| OLD | NEW |
| (Empty) | |
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. |
| 4 |
| 5 #include "embedders/openglui/common/canvas_state.h" |
| 6 |
| 7 #include <ctype.h> |
| 8 #include <string.h> |
| 9 |
| 10 #include "embedders/openglui/common/support.h" |
| 11 |
| 12 // Float parser. Does not handle exponents. This is |
| 13 // used to parse font sizes so it doesn't need to be full-blown. |
| 14 float ParseFloat(const char* s, int& pos) { |
| 15 int len = strlen(s); |
| 16 float rtn = 0.0; |
| 17 while (pos < len && s[pos] != '.' && !isdigit(s[pos])) { |
| 18 ++pos; |
| 19 } |
| 20 while (pos < len && isdigit(s[pos])) { |
| 21 rtn = rtn * 10.0 + s[pos] - '0'; |
| 22 ++pos; |
| 23 } |
| 24 if (pos < len && s[pos] == '.') { |
| 25 pos++; |
| 26 float div = 1.0; |
| 27 while (pos < len && isdigit(s[pos])) { |
| 28 rtn = rtn * 10.0 + s[pos] - '0'; |
| 29 ++pos; |
| 30 div *= 10.0; |
| 31 } |
| 32 rtn /= div; |
| 33 } |
| 34 return rtn; |
| 35 } |
| 36 |
| 37 int ParseInt(const char* s, int& pos) { |
| 38 int len = strlen(s); |
| 39 int rtn = 0; |
| 40 while (pos < len && !isdigit(s[pos])) { |
| 41 ++pos; |
| 42 } |
| 43 while (pos < len && isdigit(s[pos])) { |
| 44 rtn = rtn * 10 + s[pos] - '0'; |
| 45 ++pos; |
| 46 } |
| 47 return rtn; |
| 48 } |
| 49 |
| 50 void CanvasState::setLineCap(const char* lc) { |
| 51 if (strcmp(lc, "round") == 0) { |
| 52 paint_.setStrokeCap(SkPaint::kRound_Cap); |
| 53 } else if (strcmp(lc, "square") == 0) { |
| 54 paint_.setStrokeCap(SkPaint::kSquare_Cap); |
| 55 } else { |
| 56 paint_.setStrokeCap(SkPaint::kButt_Cap); |
| 57 } |
| 58 } |
| 59 |
| 60 void CanvasState::setLineJoin(const char* lj) { |
| 61 if (strcmp(lj, "round") == 0) { |
| 62 paint_.setStrokeJoin(SkPaint::kRound_Join); |
| 63 } else if (strcmp(lj, "bevel") == 0) { |
| 64 paint_.setStrokeJoin(SkPaint::kBevel_Join); |
| 65 } else { |
| 66 paint_.setStrokeJoin(SkPaint::kMiter_Join); |
| 67 } |
| 68 } |
| 69 |
| 70 const char* CanvasState::setFont(const char*name, float size) { |
| 71 // Font names have the form "<modifier> <size> <family>". |
| 72 // Modifiers are "normal", "italic", "bold". |
| 73 // Sizes have magnitude and units; e.g. "10pt", "20px". |
| 74 const char* rtn = name; |
| 75 if (size < 0) { |
| 76 int pos = 0; |
| 77 // TODO(gram): need to handle these modifiers. |
| 78 if (strncmp(name, "normal", 6) == 0) { |
| 79 pos = 6; |
| 80 } else if (strncmp(name, "italic", 6) == 0) { |
| 81 pos = 6; |
| 82 } else if (strncmp(name, "bold", 4) == 0) { |
| 83 pos = 4; |
| 84 } |
| 85 size = ParseFloat(name, pos); |
| 86 // Font size units: px, etc. For now just px. |
| 87 // TODO(gram): Handle other units. |
| 88 if (strncmp(name + pos, "px", 2) == 0) { |
| 89 pos += 2; |
| 90 } |
| 91 int len = strlen(name); |
| 92 while (pos < len && isspace(name[pos])) { |
| 93 ++pos; |
| 94 } |
| 95 name = name + pos; |
| 96 } |
| 97 SkTypeface *pTypeface = SkTypeface::CreateFromName(name, SkTypeface::kNormal); |
| 98 paint_.setTypeface(pTypeface); |
| 99 paint_.setTextSize(size); |
| 100 pTypeface->unref(); |
| 101 // TODO(gram): Must return a normalized font name incorporating size, so |
| 102 // callers can set the Dart canvas font name to an appropriate value. |
| 103 // Actually this may not be necessary in which case we can change this |
| 104 // method to return void. |
| 105 return rtn; |
| 106 } |
| 107 |
| 108 const char* CanvasState::setTextAlign(const char* align) { |
| 109 // TODO(gram): What about "start" and "end"? |
| 110 // I don't see any an analogs in Skia. |
| 111 if (strcmp(align, "left") == 0) { |
| 112 paint_.setTextAlign(SkPaint::kLeft_Align); |
| 113 } else if (strcmp(align, "right") == 0) { |
| 114 paint_.setTextAlign(SkPaint::kRight_Align); |
| 115 } else { |
| 116 paint_.setTextAlign(SkPaint::kCenter_Align); |
| 117 } |
| 118 return align; |
| 119 } |
| 120 |
| 121 const char* CanvasState::setTextBaseline(const char* baseline) { |
| 122 // TODO(gram): Does skia support this? It doesn't seem like |
| 123 // it. Right now we don't use the textBaseline value, but we |
| 124 // may have to implement this ourselves, by adjusting the y |
| 125 // values passed to StrokeText/FillText using the font metrics. |
| 126 if (strcmp(baseline, "top") == 0) { |
| 127 } else if (strcmp(baseline, "middle") == 0) { |
| 128 } else if (strcmp(baseline, "bottom") == 0) { |
| 129 } else if (strcmp(baseline, "hanging") == 0) { |
| 130 } else if (strcmp(baseline, "alphabetic") == 0) { |
| 131 } else if (strcmp(baseline, "ideographic") == 0) { |
| 132 } |
| 133 return baseline; |
| 134 } |
| 135 |
| 136 const char* CanvasState::setTextDirection(const char* direction) { |
| 137 // TODO(gram): Add support for this if Skia does. |
| 138 return direction; |
| 139 } |
| 140 |
| 141 void CanvasState::setGlobalCompositeOperation(const char* op) { |
| 142 SkXfermode::Mode mode; |
| 143 if (strcmp(op, "source-atop") == 0) { |
| 144 mode = SkXfermode::kSrcATop_Mode; |
| 145 } else if (strcmp(op, "source-in") == 0) { |
| 146 mode = SkXfermode::kSrcIn_Mode; |
| 147 } else if (strcmp(op, "source-out") == 0) { |
| 148 mode = SkXfermode::kSrcOut_Mode; |
| 149 } else if (strcmp(op, "source-over") == 0) { |
| 150 mode = SkXfermode::kSrcOver_Mode; // Default. |
| 151 } else if (strcmp(op, "destination-atop") == 0) { |
| 152 mode = SkXfermode::kDstATop_Mode; |
| 153 } else if (strcmp(op, "destination-in") == 0) { |
| 154 mode = SkXfermode::kDstIn_Mode; |
| 155 } else if (strcmp(op, "destination-out") == 0) { |
| 156 mode = SkXfermode::kDstOut_Mode; |
| 157 } else if (strcmp(op, "destination-over") == 0) { |
| 158 mode = SkXfermode::kDstOver_Mode; |
| 159 } else if (strcmp(op, "lighter") == 0) { |
| 160 mode = SkXfermode::kLighten_Mode; |
| 161 } else if (strcmp(op, "darker") == 0) { |
| 162 mode = SkXfermode::kDarken_Mode; |
| 163 } else if (strcmp(op, "xor") == 0) { |
| 164 mode = SkXfermode::kXor_Mode; |
| 165 } else if (strcmp(op, "copy") == 0) { |
| 166 mode = SkXfermode::kSrc_Mode; |
| 167 } |
| 168 SkXfermode* m = SkXfermode::Create(mode); |
| 169 // It seems we don't need unref() here. Including it causes |
| 170 // a crash. Maybe Skia has a preallocated long-lived set of |
| 171 // instances. |
| 172 paint_.setXfermode(m); |
| 173 } |
| 174 |
| 175 void CanvasState::Arc(float x, float y, float radius, |
| 176 float startAngle, float endAngle, |
| 177 bool antiClockwise) { |
| 178 SkRect rect; |
| 179 rect.set(x - radius, y - radius, x + radius, y + radius); |
| 180 bool doCircle = false; |
| 181 |
| 182 static float twoPi = 2 * M_PI; |
| 183 |
| 184 float sweep = endAngle - startAngle; |
| 185 if (sweep >= twoPi || sweep <= -twoPi) { |
| 186 doCircle = true; |
| 187 } |
| 188 |
| 189 if (!antiClockwise && endAngle <= startAngle) { |
| 190 endAngle += 2 * M_PI; |
| 191 } else if (antiClockwise && startAngle <= endAngle) { |
| 192 startAngle += 2 * M_PI; |
| 193 } |
| 194 sweep = endAngle - startAngle; |
| 195 |
| 196 startAngle = fmodf(startAngle, twoPi); |
| 197 float sa = Radians2Degrees(startAngle); |
| 198 float ea = Radians2Degrees(sweep); |
| 199 path_->arcTo(rect, sa, ea, false); |
| 200 if (doCircle) { |
| 201 SkPath tmp; |
| 202 tmp.addOval(rect); |
| 203 tmp.addPath(*path_); |
| 204 path_->swap(tmp); |
| 205 } |
| 206 } |
| 207 |
| 208 int hexDigit(char c) { |
| 209 if (c >= '0' && c <= '9') return c - '0'; |
| 210 if (c <= 'Z') return c - 'A' + 10; |
| 211 return c - 'a' + 10; |
| 212 } |
| 213 |
| 214 // Color parser. |
| 215 // See http://www.w3.org/TR/CSS21/syndata.html#color-units. |
| 216 // There is also another format: hsl(240,100%,100%) (and hsla) |
| 217 // TODO(gram): We probably eventually want to use a table rather |
| 218 // than a big if statement. |
| 219 ColorRGBA CanvasState::GetColor(const char* color) { |
| 220 if (color[0] == '#') { |
| 221 int r, g, b; |
| 222 if (strlen(color) == 7) { |
| 223 r = hexDigit(color[1]) * 16 + hexDigit(color[2]); |
| 224 g = hexDigit(color[3]) * 16 + hexDigit(color[4]); |
| 225 b = hexDigit(color[5]) * 16 + hexDigit(color[6]); |
| 226 } else if (strlen(color) == 4) { |
| 227 r = hexDigit(color[1]) * 16 + hexDigit(color[1]); |
| 228 g = hexDigit(color[2]) * 16 + hexDigit(color[2]); |
| 229 b = hexDigit(color[3]) * 16 + hexDigit(color[3]); |
| 230 } |
| 231 return ColorRGBA(r, g, b); |
| 232 } else if (strcmp(color, "maroon") == 0) { |
| 233 return ColorRGBA(0x80, 0x00, 0x00); |
| 234 } else if (strcmp(color, "red") == 0) { |
| 235 return ColorRGBA(0xFF, 0x00, 0x00); |
| 236 } else if (strcmp(color, "orange") == 0) { |
| 237 return ColorRGBA(0xFF, 0xA5, 0x00); |
| 238 } else if (strcmp(color, "yellow") == 0) { |
| 239 return ColorRGBA(0xFF, 0xFF, 0x00); |
| 240 } else if (strcmp(color, "olive") == 0) { |
| 241 return ColorRGBA(0x80, 0x80, 0x00); |
| 242 } else if (strcmp(color, "purple") == 0) { |
| 243 return ColorRGBA(0x80, 0x00, 0x80); |
| 244 } else if (strcmp(color, "fuschia") == 0) { |
| 245 return ColorRGBA(0xFF, 0x00, 0xFF); |
| 246 } else if (strcmp(color, "white") == 0) { |
| 247 return ColorRGBA(0xFF, 0xFF, 0xFF); |
| 248 } else if (strcmp(color, "lime") == 0) { |
| 249 return ColorRGBA(0x00, 0xFF, 0x00); |
| 250 } else if (strcmp(color, "green") == 0) { |
| 251 return ColorRGBA(0x00, 0x80, 0x00); |
| 252 } else if (strcmp(color, "navy") == 0) { |
| 253 return ColorRGBA(0x00, 0x00, 0x80); |
| 254 } else if (strcmp(color, "blue") == 0) { |
| 255 return ColorRGBA(0x00, 0x00, 0xFF); |
| 256 } else if (strcmp(color, "aqua") == 0) { |
| 257 return ColorRGBA(0x00, 0xFF, 0xFF); |
| 258 } else if (strcmp(color, "teal") == 0) { |
| 259 return ColorRGBA(0x00, 0x80, 0x80); |
| 260 } else if (strcmp(color, "silver") == 0) { |
| 261 return ColorRGBA(0xC0, 0xC0, 0xC0); |
| 262 } else if (strcmp(color, "gray") == 0) { |
| 263 return ColorRGBA(0x80, 0x80, 0x80); |
| 264 } else if (strncmp(color, "rgb(", 4) == 0) { |
| 265 int pos = 4; |
| 266 int r = ParseInt(color, pos); |
| 267 ++pos; |
| 268 int g = ParseInt(color, pos); |
| 269 ++pos; |
| 270 int b = ParseInt(color, pos); |
| 271 return ColorRGBA(r, g, b); |
| 272 } else if (strncmp(color, "rgba(", 5) == 0) { |
| 273 int pos = 5; |
| 274 int r = ParseInt(color, pos); |
| 275 ++pos; |
| 276 int g = ParseInt(color, pos); |
| 277 ++pos; |
| 278 int b = ParseInt(color, pos); |
| 279 ++pos; |
| 280 float a = ParseFloat(color, pos); |
| 281 return ColorRGBA(r, g, b, static_cast<int>(a * 255.0)); |
| 282 } |
| 283 // Default to black. |
| 284 return ColorRGBA(0x00, 0x00, 0x00); |
| 285 } |
| 286 |
| 287 void CanvasState::DrawImage(const SkBitmap& bm, |
| 288 int sx, int sy, int sw, int sh, |
| 289 int dx, int dy, int dw, int dh) { |
| 290 if (sw < 0) sw = bm.width(); |
| 291 if (dw < 0) dw = bm.width(); |
| 292 if (sh < 0) sh = bm.height(); |
| 293 if (dh < 0) dh = bm.height(); |
| 294 SkIRect src = SkIRect::MakeXYWH(sx, sy, sw, sh); |
| 295 SkRect dst = SkRect::MakeXYWH(dx, dy, dw, dh); |
| 296 LOGI("DrawImage(_,%d,%d,%d,%d,%d,%d,%d,%d)", sx, sy, sw, sh, dx, dy, dw, dh); |
| 297 canvas_->drawBitmapRect(bm, &src, dst); |
| 298 } |
| 299 |
| OLD | NEW |