| OLD | NEW |
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 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 | 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. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 /** Representations of CSS styles. */ | 5 /** Representations of CSS styles. */ |
| 6 | 6 |
| 7 part of csslib.parser; | 7 part of csslib.parser; |
| 8 | 8 |
| 9 // TODO(terry): Prune down this file we do need some of the code in this file | 9 // TODO(terry): Prune down this file we do need some of the code in this file |
| 10 // for darker, lighter, how to represent a Font, etc but alot of | 10 // for darker, lighter, how to represent a Font, etc but alot of |
| (...skipping 11 matching lines...) Expand all Loading... |
| 22 * | 22 * |
| 23 * E.g., if property is color then expression could be rgba(255,255,0) the | 23 * E.g., if property is color then expression could be rgba(255,255,0) the |
| 24 * CSS declaration would be 'color:rgba(255,255,0);'. | 24 * CSS declaration would be 'color:rgba(255,255,0);'. |
| 25 * | 25 * |
| 26 * then _cssExpression would return 'rgba(255,255,0)'. See | 26 * then _cssExpression would return 'rgba(255,255,0)'. See |
| 27 * <http://www.w3.org/TR/CSS21/grammar.html> | 27 * <http://www.w3.org/TR/CSS21/grammar.html> |
| 28 */ | 28 */ |
| 29 String get cssExpression; | 29 String get cssExpression; |
| 30 } | 30 } |
| 31 | 31 |
| 32 | |
| 33 /** | 32 /** |
| 34 * Base interface for Color, HSL and RGB. | 33 * Base interface for Color, HSL and RGB. |
| 35 */ | 34 */ |
| 36 abstract class ColorBase { | 35 abstract class ColorBase { |
| 37 /** | 36 /** |
| 38 * Canonical form for color #rrggbb with alpha blending (0.0 == full | 37 * Canonical form for color #rrggbb with alpha blending (0.0 == full |
| 39 * transparency and 1.0 == fully opaque). If _argb length is 6 it's an | 38 * transparency and 1.0 == fully opaque). If _argb length is 6 it's an |
| 40 * rrggbb otherwise it's aarrggbb. | 39 * rrggbb otherwise it's aarrggbb. |
| 41 */ | 40 */ |
| 42 String toHexArgbString(); | 41 String toHexArgbString(); |
| 43 | 42 |
| 44 /** | 43 /** |
| 45 * Return argb as a value (int). | 44 * Return argb as a value (int). |
| 46 */ | 45 */ |
| 47 int get argbValue; | 46 int get argbValue; |
| 48 } | 47 } |
| 49 | 48 |
| 50 | |
| 51 /** | 49 /** |
| 52 * General purpse Color class. Represent a color as an ARGB value that can be | 50 * General purpse Color class. Represent a color as an ARGB value that can be |
| 53 * converted to and from num, hex string, hsl, hsla, rgb, rgba and SVG pre- | 51 * converted to and from num, hex string, hsl, hsla, rgb, rgba and SVG pre- |
| 54 * defined color constant. | 52 * defined color constant. |
| 55 */ | 53 */ |
| 56 class Color implements _StyleProperty, ColorBase { | 54 class Color implements _StyleProperty, ColorBase { |
| 57 // If _argb length is 6 it's an rrggbb otherwise it's aarrggbb. | 55 // If _argb length is 6 it's an rrggbb otherwise it's aarrggbb. |
| 58 final String _argb; | 56 final String _argb; |
| 59 | 57 |
| 60 // TODO(terry): Look at reducing Rgba and Hsla classes as factories for | 58 // TODO(terry): Look at reducing Rgba and Hsla classes as factories for |
| 61 // converting from Color to an Rgba or Hsla for reading only. | 59 // converting from Color to an Rgba or Hsla for reading only. |
| 62 // Usefulness of creating an Rgba or Hsla is limited. | 60 // Usefulness of creating an Rgba or Hsla is limited. |
| 63 | 61 |
| 64 /** | 62 /** |
| 65 * Create a color with an integer representing the rgb value of red, green, | 63 * Create a color with an integer representing the rgb value of red, green, |
| 66 * and blue. The value 0xffffff is the color white #ffffff (CSS style). | 64 * and blue. The value 0xffffff is the color white #ffffff (CSS style). |
| 67 * The [rgb] value of 0xffd700 would map to #ffd700 or the constant | 65 * The [rgb] value of 0xffd700 would map to #ffd700 or the constant |
| 68 * Color.gold, where ff is red intensity, d7 is green intensity, and 00 is | 66 * Color.gold, where ff is red intensity, d7 is green intensity, and 00 is |
| 69 * blue intensity. | 67 * blue intensity. |
| 70 */ | 68 */ |
| 71 Color(int rgb, [num alpha]) : | 69 Color(int rgb, [num alpha]) : this._argb = Color._rgbToArgbString(rgb, alpha); |
| 72 this._argb = Color._rgbToArgbString(rgb, alpha); | |
| 73 | 70 |
| 74 /** | 71 /** |
| 75 * RGB takes three values. The [red], [green], and [blue] parameters are | 72 * RGB takes three values. The [red], [green], and [blue] parameters are |
| 76 * the intensity of those components where '0' is the least and '256' is the | 73 * the intensity of those components where '0' is the least and '256' is the |
| 77 * greatest. | 74 * greatest. |
| 78 * | 75 * |
| 79 * If [alpha] is provided, it is the level of translucency which ranges from | 76 * If [alpha] is provided, it is the level of translucency which ranges from |
| 80 * '0' (completely transparent) to '1.0' (completely opaque). It will | 77 * '0' (completely transparent) to '1.0' (completely opaque). It will |
| 81 * internally be mapped to an int between '0' and '255' like the other color | 78 * internally be mapped to an int between '0' and '255' like the other color |
| 82 * components. | 79 * components. |
| 83 */ | 80 */ |
| 84 Color.createRgba(int red, int green, int blue, [num alpha]) : | 81 Color.createRgba(int red, int green, int blue, [num alpha]) |
| 85 this._argb = Color.convertToHexString(Color._clamp(red, 0, 255), | 82 : this._argb = Color.convertToHexString(Color._clamp(red, 0, 255), |
| 86 Color._clamp(green, 0, 255), | 83 Color._clamp(green, 0, 255), Color._clamp(blue, 0, 255), |
| 87 Color._clamp(blue, 0, 255), | |
| 88 alpha != null ? Color._clamp(alpha, 0, 1) : alpha); | 84 alpha != null ? Color._clamp(alpha, 0, 1) : alpha); |
| 89 | 85 |
| 90 /** | 86 /** |
| 91 * Creates a new color from a CSS color string. For more information, see | 87 * Creates a new color from a CSS color string. For more information, see |
| 92 * <https://developer.mozilla.org/en/CSS/color>. | 88 * <https://developer.mozilla.org/en/CSS/color>. |
| 93 */ | 89 */ |
| 94 Color.css(String color) : | 90 Color.css(String color) : this._argb = Color._convertCssToArgb(color); |
| 95 this._argb = Color._convertCssToArgb(color); | |
| 96 | 91 |
| 97 // TODO(jmesserly): I found the use of percents a bit suprising. | 92 // TODO(jmesserly): I found the use of percents a bit suprising. |
| 98 /** | 93 /** |
| 99 * HSL takes three values. The [hueDegree] degree on the color wheel; '0' is | 94 * HSL takes three values. The [hueDegree] degree on the color wheel; '0' is |
| 100 * the least and '100' is the greatest. The value '0' or '360' is red, '120' | 95 * the least and '100' is the greatest. The value '0' or '360' is red, '120' |
| 101 * is green, '240' is blue. Numbers in between reflect different shades. | 96 * is green, '240' is blue. Numbers in between reflect different shades. |
| 102 * The [saturationPercent] percentage; where'0' is the least and '100' is the | 97 * The [saturationPercent] percentage; where'0' is the least and '100' is the |
| 103 * greatest (100 represents full color). The [lightnessPercent] percentage; | 98 * greatest (100 represents full color). The [lightnessPercent] percentage; |
| 104 * where'0' is the least and '100' is the greatest. The value 0 is dark or | 99 * where'0' is the least and '100' is the greatest. The value 0 is dark or |
| 105 * black, 100 is light or white and 50 is a medium lightness. | 100 * black, 100 is light or white and 50 is a medium lightness. |
| 106 * | 101 * |
| 107 * If [alpha] is provided, it is the level of translucency which ranges from | 102 * If [alpha] is provided, it is the level of translucency which ranges from |
| 108 * '0' (completely transparent foreground) to '1.0' (completely opaque | 103 * '0' (completely transparent foreground) to '1.0' (completely opaque |
| 109 * foreground). | 104 * foreground). |
| 110 */ | 105 */ |
| 111 Color.createHsla(num hueDegree, num saturationPercent, num lightnessPercent, | 106 Color.createHsla(num hueDegree, num saturationPercent, num lightnessPercent, |
| 112 [num alpha]) : | 107 [num alpha]) |
| 113 this._argb = new Hsla(Color._clamp(hueDegree, 0, 360) / 360, | 108 : this._argb = new Hsla(Color._clamp(hueDegree, 0, 360) / 360, |
| 114 Color._clamp(saturationPercent, 0, 100) / 100, | 109 Color._clamp(saturationPercent, 0, 100) / 100, |
| 115 Color._clamp(lightnessPercent, 0, 100) / 100, | 110 Color._clamp(lightnessPercent, 0, 100) / 100, |
| 116 alpha != null ? Color._clamp(alpha, 0, 1) : alpha).toHexArgbString(); | 111 alpha != null ? Color._clamp(alpha, 0, 1) : alpha).toHexArgbString(); |
| 117 | 112 |
| 118 /** | 113 /** |
| 119 * The hslaRaw takes three values. The [hue] degree on the color wheel; '0' | 114 * The hslaRaw takes three values. The [hue] degree on the color wheel; '0' |
| 120 * is the least and '1' is the greatest. The value '0' or '1' is red, the | 115 * is the least and '1' is the greatest. The value '0' or '1' is red, the |
| 121 * ratio of 120/360 is green, and the ratio of 240/360 is blue. Numbers in | 116 * ratio of 120/360 is green, and the ratio of 240/360 is blue. Numbers in |
| 122 * between reflect different shades. The [saturation] is a percentage; '0' | 117 * between reflect different shades. The [saturation] is a percentage; '0' |
| 123 * is the least and '1' is the greatest. The value of '1' is equivalent to | 118 * is the least and '1' is the greatest. The value of '1' is equivalent to |
| 124 * 100% (full colour). The [lightness] is a percentage; '0' is the least and | 119 * 100% (full colour). The [lightness] is a percentage; '0' is the least and |
| 125 * '1' is the greatest. The value of '0' is dark (black), the value of '1' | 120 * '1' is the greatest. The value of '0' is dark (black), the value of '1' |
| 126 * is light (white), and the value of '.50' is a medium lightness. | 121 * is light (white), and the value of '.50' is a medium lightness. |
| 127 * | 122 * |
| 128 * The fourth optional parameter is: | 123 * The fourth optional parameter is: |
| 129 * [alpha] level of translucency range of values is 0..1, zero is a | 124 * [alpha] level of translucency range of values is 0..1, zero is a |
| 130 * completely transparent foreground and 1 is a completely | 125 * completely transparent foreground and 1 is a completely |
| 131 * opaque foreground. | 126 * opaque foreground. |
| 132 */ | 127 */ |
| 133 Color.hslaRaw(num hue, num saturation, num lightness, [num alpha]) : | 128 Color.hslaRaw(num hue, num saturation, num lightness, [num alpha]) |
| 134 this._argb = new Hsla(Color._clamp(hue, 0, 1), | 129 : this._argb = new Hsla(Color._clamp(hue, 0, 1), |
| 135 Color._clamp(saturation, 0, 1), | 130 Color._clamp(saturation, 0, 1), Color._clamp(lightness, 0, 1), |
| 136 Color._clamp(lightness, 0, 1), | |
| 137 alpha != null ? Color._clamp(alpha, 0, 1) : alpha).toHexArgbString(); | 131 alpha != null ? Color._clamp(alpha, 0, 1) : alpha).toHexArgbString(); |
| 138 | 132 |
| 139 /** | 133 /** |
| 140 * Generate a real constant for pre-defined colors (no leading #). | 134 * Generate a real constant for pre-defined colors (no leading #). |
| 141 */ | 135 */ |
| 142 const Color.hex(this._argb); | 136 const Color.hex(this._argb); |
| 143 | 137 |
| 144 // TODO(jmesserly): this is needed by the example so leave it exposed for now. | 138 // TODO(jmesserly): this is needed by the example so leave it exposed for now. |
| 145 String toString() => cssExpression; | 139 String toString() => cssExpression; |
| 146 | 140 |
| 147 // TODO(terry): Regardless of how color is set (rgb, num, css or hsl) we'll | 141 // TODO(terry): Regardless of how color is set (rgb, num, css or hsl) we'll |
| 148 // always return a rgb or rgba loses fidelity when debugging in | 142 // always return a rgb or rgba loses fidelity when debugging in |
| 149 // CSS if user uses hsl and would like to edit as hsl, etc. If | 143 // CSS if user uses hsl and would like to edit as hsl, etc. If |
| 150 // this is an issue we should keep the original value and not re- | 144 // this is an issue we should keep the original value and not re- |
| 151 // create the CSS from the normalized value. | 145 // create the CSS from the normalized value. |
| 152 String get cssExpression { | 146 String get cssExpression { |
| 153 if (_argb.length == 6) { | 147 if (_argb.length == 6) { |
| 154 return "#$_argb"; // RGB only, no alpha blending. | 148 return "#$_argb"; // RGB only, no alpha blending. |
| 155 } else { | 149 } else { |
| 156 num alpha = Color.hexToInt(_argb.substring(0, 2)); | 150 num alpha = Color.hexToInt(_argb.substring(0, 2)); |
| 157 String a = (alpha / 255).toStringAsPrecision(2); | 151 String a = (alpha / 255).toStringAsPrecision(2); |
| 158 int r = Color.hexToInt(_argb.substring(2, 4)); | 152 int r = Color.hexToInt(_argb.substring(2, 4)); |
| 159 int g = Color.hexToInt(_argb.substring(4, 6)); | 153 int g = Color.hexToInt(_argb.substring(4, 6)); |
| 160 int b = Color.hexToInt(_argb.substring(6, 8)); | 154 int b = Color.hexToInt(_argb.substring(6, 8)); |
| 161 return "rgba($r,$g,$b,$a)"; | 155 return "rgba($r,$g,$b,$a)"; |
| 162 } | 156 } |
| 163 } | 157 } |
| 164 | 158 |
| (...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 239 /** | 233 /** |
| 240 * Parse CSS expressions of the from #rgb, rgb(r,g,b), rgba(r,g,b,a), | 234 * Parse CSS expressions of the from #rgb, rgb(r,g,b), rgba(r,g,b,a), |
| 241 * hsl(h,s,l), hsla(h,s,l,a) and SVG colors (e.g., darkSlateblue, etc.) and | 235 * hsl(h,s,l), hsla(h,s,l,a) and SVG colors (e.g., darkSlateblue, etc.) and |
| 242 * convert to argb. | 236 * convert to argb. |
| 243 */ | 237 */ |
| 244 static String _convertCssToArgb(String value) { | 238 static String _convertCssToArgb(String value) { |
| 245 // TODO(terry): Better parser/regex for converting CSS properties. | 239 // TODO(terry): Better parser/regex for converting CSS properties. |
| 246 String color = value.trim().replaceAll("\\s", ""); | 240 String color = value.trim().replaceAll("\\s", ""); |
| 247 if (color[0] == '#') { | 241 if (color[0] == '#') { |
| 248 String v = color.substring(1); | 242 String v = color.substring(1); |
| 249 Color.hexToInt(v); // Valid hexadecimal, throws if not. | 243 Color.hexToInt(v); // Valid hexadecimal, throws if not. |
| 250 return v; | 244 return v; |
| 251 } else if (color.length > 0 && color[color.length - 1] == ')') { | 245 } else if (color.length > 0 && color[color.length - 1] == ')') { |
| 252 int type; | 246 int type; |
| 253 if (color.indexOf("rgb(") == 0 || color.indexOf("RGB(") == 0) { | 247 if (color.indexOf("rgb(") == 0 || color.indexOf("RGB(") == 0) { |
| 254 color = color.substring(4); | 248 color = color.substring(4); |
| 255 type = _rgbCss; | 249 type = _rgbCss; |
| 256 } else if (color.indexOf("rgba(") == 0 || color.indexOf("RGBA(") == 0) { | 250 } else if (color.indexOf("rgba(") == 0 || color.indexOf("RGBA(") == 0) { |
| 257 type = _rgbaCss; | 251 type = _rgbaCss; |
| 258 color = color.substring(5); | 252 color = color.substring(5); |
| 259 } else if (color.indexOf("hsl(") == 0 || color.indexOf("HSL(") == 0) { | 253 } else if (color.indexOf("hsl(") == 0 || color.indexOf("HSL(") == 0) { |
| 260 type = _hslCss; | 254 type = _hslCss; |
| 261 color = color.substring(4); | 255 color = color.substring(4); |
| 262 } else if (color.indexOf("hsla(") == 0 || color.indexOf("HSLA(") == 0) { | 256 } else if (color.indexOf("hsla(") == 0 || color.indexOf("HSLA(") == 0) { |
| 263 type = _hslaCss; | 257 type = _hslaCss; |
| 264 color = color.substring(5); | 258 color = color.substring(5); |
| 265 } else { | 259 } else { |
| 266 throw new UnsupportedError('CSS property not implemented'); | 260 throw new UnsupportedError('CSS property not implemented'); |
| 267 } | 261 } |
| 268 | 262 |
| 269 color = color.substring(0, color.length - 1); // Strip close paren. | 263 color = color.substring(0, color.length - 1); // Strip close paren. |
| 270 | 264 |
| 271 var args = <num>[]; | 265 var args = <num>[]; |
| 272 List<String> params = color.split(","); | 266 List<String> params = color.split(","); |
| 273 for (String param in params) { | 267 for (String param in params) { |
| 274 args.add(double.parse(param)); | 268 args.add(double.parse(param)); |
| 275 } | 269 } |
| 276 switch (type) { | 270 switch (type) { |
| 277 case _rgbCss: | 271 case _rgbCss: |
| 278 return Color.convertToHexString(args[0], args[1], args[2]); | 272 return Color.convertToHexString(args[0], args[1], args[2]); |
| 279 case _rgbaCss: | 273 case _rgbaCss: |
| 280 return Color.convertToHexString(args[0], args[1], args[2], args[3]); | 274 return Color.convertToHexString(args[0], args[1], args[2], args[3]); |
| 281 case _hslCss: | 275 case _hslCss: |
| 282 return new Hsla(args[0], args[1], args[2]).toHexArgbString(); | 276 return new Hsla(args[0], args[1], args[2]).toHexArgbString(); |
| 283 case _hslaCss: | 277 case _hslaCss: |
| 284 return new Hsla(args[0], args[1], args[2], | 278 return new Hsla(args[0], args[1], args[2], args[3]).toHexArgbString(); |
| 285 args[3]).toHexArgbString(); | |
| 286 default: | 279 default: |
| 287 // Type not defined UnsupportedOperationException should have thrown. | 280 // Type not defined UnsupportedOperationException should have thrown. |
| 288 assert(true); | 281 assert(true); |
| 289 break; | 282 break; |
| 290 } | 283 } |
| 291 } | 284 } |
| 292 } | 285 } |
| 293 | 286 |
| 294 static int hexToInt(String hex) => int.parse(hex, radix: 16); | 287 static int hexToInt(String hex) => int.parse(hex, radix: 16); |
| 295 | 288 |
| 296 static String convertToHexString(int r, int g, int b, [num a]) { | 289 static String convertToHexString(int r, int g, int b, [num a]) { |
| 297 String rHex = Color._numAs2DigitHex(Color._clamp(r, 0, 255)); | 290 String rHex = Color._numAs2DigitHex(Color._clamp(r, 0, 255)); |
| 298 String gHex = Color._numAs2DigitHex(Color._clamp(g, 0, 255)); | 291 String gHex = Color._numAs2DigitHex(Color._clamp(g, 0, 255)); |
| 299 String bHex = Color._numAs2DigitHex(Color._clamp(b, 0, 255)); | 292 String bHex = Color._numAs2DigitHex(Color._clamp(b, 0, 255)); |
| 300 String aHex = (a != null) ? | 293 String aHex = (a != null) |
| 301 Color._numAs2DigitHex((Color._clamp(a, 0, 1) * 255).round()) : ""; | 294 ? Color._numAs2DigitHex((Color._clamp(a, 0, 1) * 255).round()) |
| 295 : ""; |
| 302 | 296 |
| 303 // TODO(terry) 15.toRadixString(16) return 'F' on Dartium not f as in JS. | 297 // TODO(terry) 15.toRadixString(16) return 'F' on Dartium not f as in JS. |
| 304 // bug: <http://code.google.com/p/dart/issues/detail?id=2670> | 298 // bug: <http://code.google.com/p/dart/issues/detail?id=2670> |
| 305 return "$aHex$rHex$gHex$bHex".toLowerCase(); | 299 return "$aHex$rHex$gHex$bHex".toLowerCase(); |
| 306 } | 300 } |
| 307 | 301 |
| 308 static String _numAs2DigitHex(num v) { | 302 static String _numAs2DigitHex(num v) { |
| 309 // TODO(terry): v.toInt().toRadixString instead of v.toRadixString | 303 // TODO(terry): v.toInt().toRadixString instead of v.toRadixString |
| 310 // Bug <http://code.google.com/p/dart/issues/detail?id=2671>. | 304 // Bug <http://code.google.com/p/dart/issues/detail?id=2671>. |
| 311 String hex = v.toInt().toRadixString(16); | 305 String hex = v.toInt().toRadixString(16); |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 354 /** | 348 /** |
| 355 * The parameter [v] is the color to change (r, g, or b) in the range '0' to | 349 * The parameter [v] is the color to change (r, g, or b) in the range '0' to |
| 356 * '255'. The parameter [delta] is a number between '-1' and '1'. A value | 350 * '255'. The parameter [delta] is a number between '-1' and '1'. A value |
| 357 * between '-1' and '0' is darker and a value between '0' and '1' is lighter | 351 * between '-1' and '0' is darker and a value between '0' and '1' is lighter |
| 358 * ('0' imples no change). | 352 * ('0' imples no change). |
| 359 */ | 353 */ |
| 360 static num _changeTintShadeColor(num v, num delta) => | 354 static num _changeTintShadeColor(num v, num delta) => |
| 361 Color._clamp(((1 - delta) * v + (delta * 255)).round(), 0, 255); | 355 Color._clamp(((1 - delta) * v + (delta * 255)).round(), 0, 255); |
| 362 | 356 |
| 363 // Predefined CSS colors see <http://www.w3.org/TR/css3-color/> | 357 // Predefined CSS colors see <http://www.w3.org/TR/css3-color/> |
| 364 static final Color transparent = const Color.hex("00ffffff"); // Alpha 0.0 | 358 static final Color transparent = const Color.hex("00ffffff"); // Alpha 0.0 |
| 365 static final Color aliceBlue = const Color.hex("0f08ff"); | 359 static final Color aliceBlue = const Color.hex("0f08ff"); |
| 366 static final Color antiqueWhite = const Color.hex("0faebd7"); | 360 static final Color antiqueWhite = const Color.hex("0faebd7"); |
| 367 static final Color aqua = const Color.hex("00ffff"); | 361 static final Color aqua = const Color.hex("00ffff"); |
| 368 static final Color aquaMarine = const Color.hex("7fffd4"); | 362 static final Color aquaMarine = const Color.hex("7fffd4"); |
| 369 static final Color azure = const Color.hex("f0ffff"); | 363 static final Color azure = const Color.hex("f0ffff"); |
| 370 static final Color beige = const Color.hex("f5f5dc"); | 364 static final Color beige = const Color.hex("f5f5dc"); |
| 371 static final Color bisque = const Color.hex("ffe4c4"); | 365 static final Color bisque = const Color.hex("ffe4c4"); |
| 372 static final Color black = const Color.hex("000000"); | 366 static final Color black = const Color.hex("000000"); |
| 373 static final Color blanchedAlmond = const Color.hex("ffebcd"); | 367 static final Color blanchedAlmond = const Color.hex("ffebcd"); |
| 374 static final Color blue = const Color.hex("0000ff"); | 368 static final Color blue = const Color.hex("0000ff"); |
| (...skipping 129 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 504 static final Color tomato = const Color.hex("ff6347"); | 498 static final Color tomato = const Color.hex("ff6347"); |
| 505 static final Color turquoise = const Color.hex("40e0d0"); | 499 static final Color turquoise = const Color.hex("40e0d0"); |
| 506 static final Color violet = const Color.hex("ee82ee"); | 500 static final Color violet = const Color.hex("ee82ee"); |
| 507 static final Color wheat = const Color.hex("f5deb3"); | 501 static final Color wheat = const Color.hex("f5deb3"); |
| 508 static final Color white = const Color.hex("ffffff"); | 502 static final Color white = const Color.hex("ffffff"); |
| 509 static final Color whiteSmoke = const Color.hex("f5f5f5"); | 503 static final Color whiteSmoke = const Color.hex("f5f5f5"); |
| 510 static final Color yellow = const Color.hex("ffff00"); | 504 static final Color yellow = const Color.hex("ffff00"); |
| 511 static final Color yellowGreen = const Color.hex("9acd32"); | 505 static final Color yellowGreen = const Color.hex("9acd32"); |
| 512 } | 506 } |
| 513 | 507 |
| 514 | |
| 515 /** | 508 /** |
| 516 * Rgba class for users that want to interact with a color as a RGBA value. | 509 * Rgba class for users that want to interact with a color as a RGBA value. |
| 517 */ | 510 */ |
| 518 class Rgba implements _StyleProperty, ColorBase { | 511 class Rgba implements _StyleProperty, ColorBase { |
| 519 // TODO(terry): Consider consolidating rgba to a single 32-bit int, make sure | 512 // TODO(terry): Consider consolidating rgba to a single 32-bit int, make sure |
| 520 // it works under JS and Dart VM. | 513 // it works under JS and Dart VM. |
| 521 final int r; | 514 final int r; |
| 522 final int g; | 515 final int g; |
| 523 final int b; | 516 final int b; |
| 524 final num a; | 517 final num a; |
| 525 | 518 |
| 526 Rgba(int red, int green, int blue, [num alpha]) : | 519 Rgba(int red, int green, int blue, [num alpha]) |
| 527 this.r = Color._clamp(red, 0, 255), | 520 : this.r = Color._clamp(red, 0, 255), |
| 528 this.g = Color._clamp(green, 0, 255), | 521 this.g = Color._clamp(green, 0, 255), |
| 529 this.b = Color._clamp(blue, 0, 255), | 522 this.b = Color._clamp(blue, 0, 255), |
| 530 this.a = (alpha != null) ? Color._clamp(alpha, 0, 1) : alpha; | 523 this.a = (alpha != null) ? Color._clamp(alpha, 0, 1) : alpha; |
| 531 | 524 |
| 532 factory Rgba.fromString(String hexValue) => | 525 factory Rgba.fromString(String hexValue) => |
| 533 new Color.css("#${Color._convertCssToArgb(hexValue)}").rgba; | 526 new Color.css("#${Color._convertCssToArgb(hexValue)}").rgba; |
| 534 | 527 |
| 535 factory Rgba.fromColor(Color color) => color.rgba; | 528 factory Rgba.fromColor(Color color) => color.rgba; |
| 536 | 529 |
| 537 factory Rgba.fromArgbValue(num value) { | 530 factory Rgba.fromArgbValue(num value) { |
| 538 return new Rgba(((value.toInt() & 0xff000000) >> 0x18), /* a */ | 531 return new Rgba(((value.toInt() & 0xff000000) >> 0x18), /* a */ |
| 539 ((value.toInt() & 0xff0000) >> 0x10), /* r */ | 532 ((value.toInt() & 0xff0000) >> 0x10), /* r */ |
| 540 ((value.toInt() & 0xff00) >> 8), /* g */ | 533 ((value.toInt() & 0xff00) >> 8), /* g */ |
| 541 ((value.toInt() & 0xff))); /* b */ | 534 ((value.toInt() & 0xff))); /* b */ |
| 542 } | 535 } |
| 543 | 536 |
| 544 factory Rgba.fromHsla(Hsla hsla) { | 537 factory Rgba.fromHsla(Hsla hsla) { |
| 545 // Convert to Rgba. | 538 // Convert to Rgba. |
| 546 // See site <http://easyrgb.com/index.php?X=MATH> for good documentation | 539 // See site <http://easyrgb.com/index.php?X=MATH> for good documentation |
| 547 // and color conversion routines. | 540 // and color conversion routines. |
| 548 | 541 |
| 549 num h = hsla.hue; | 542 num h = hsla.hue; |
| 550 num s = hsla.saturation; | 543 num s = hsla.saturation; |
| 551 num l = hsla.lightness; | 544 num l = hsla.lightness; |
| (...skipping 10 matching lines...) Expand all Loading... |
| 562 } else { | 555 } else { |
| 563 num var2; | 556 num var2; |
| 564 | 557 |
| 565 if (l < 0.5) { | 558 if (l < 0.5) { |
| 566 var2 = l * (1 + s); | 559 var2 = l * (1 + s); |
| 567 } else { | 560 } else { |
| 568 var2 = (l + s) - (s * l); | 561 var2 = (l + s) - (s * l); |
| 569 } | 562 } |
| 570 num var1 = 2 * l - var2; | 563 num var1 = 2 * l - var2; |
| 571 | 564 |
| 572 r = (255 * Rgba._hueToRGB(var1, var2, h + (1/3))).round().toInt(); | 565 r = (255 * Rgba._hueToRGB(var1, var2, h + (1 / 3))).round().toInt(); |
| 573 g = (255 * Rgba._hueToRGB(var1, var2, h)).round().toInt(); | 566 g = (255 * Rgba._hueToRGB(var1, var2, h)).round().toInt(); |
| 574 b = (255 * Rgba._hueToRGB(var1, var2, h - (1/3))).round().toInt(); | 567 b = (255 * Rgba._hueToRGB(var1, var2, h - (1 / 3))).round().toInt(); |
| 575 } | 568 } |
| 576 | 569 |
| 577 return new Rgba(r, g, b, a); | 570 return new Rgba(r, g, b, a); |
| 578 } | 571 } |
| 579 | 572 |
| 580 static num _hueToRGB(num v1, num v2, num vH) { | 573 static num _hueToRGB(num v1, num v2, num vH) { |
| 581 if (vH < 0) { | 574 if (vH < 0) { |
| 582 vH += 1; | 575 vH += 1; |
| 583 } | 576 } |
| 584 | 577 |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 625 | 618 |
| 626 Color get color => new Color.createRgba(r, g, b, a); | 619 Color get color => new Color.createRgba(r, g, b, a); |
| 627 Hsla get hsla => new Hsla.fromRgba(this); | 620 Hsla get hsla => new Hsla.fromRgba(this); |
| 628 | 621 |
| 629 Rgba darker(num amount) => Color._createNewTintShadeFromRgba(this, -amount); | 622 Rgba darker(num amount) => Color._createNewTintShadeFromRgba(this, -amount); |
| 630 Rgba lighter(num amount) => Color._createNewTintShadeFromRgba(this, amount); | 623 Rgba lighter(num amount) => Color._createNewTintShadeFromRgba(this, amount); |
| 631 | 624 |
| 632 int get hashCode => toHexArgbString().hashCode; | 625 int get hashCode => toHexArgbString().hashCode; |
| 633 } | 626 } |
| 634 | 627 |
| 635 | |
| 636 /** | 628 /** |
| 637 * Hsl class support to interact with a color as a hsl with hue, saturation, and | 629 * Hsl class support to interact with a color as a hsl with hue, saturation, and |
| 638 * lightness with optional alpha blending. The hue is a ratio of 360 degrees | 630 * lightness with optional alpha blending. The hue is a ratio of 360 degrees |
| 639 * 360° = 1 or 0, (1° == (1/360)), saturation and lightness is a 0..1 fraction | 631 * 360° = 1 or 0, (1° == (1/360)), saturation and lightness is a 0..1 fraction |
| 640 * (1 == 100%) and alpha is a 0..1 fraction. | 632 * (1 == 100%) and alpha is a 0..1 fraction. |
| 641 */ | 633 */ |
| 642 class Hsla implements _StyleProperty, ColorBase { | 634 class Hsla implements _StyleProperty, ColorBase { |
| 643 final num _h; // Value from 0..1 | 635 final num _h; // Value from 0..1 |
| 644 final num _s; // Value from 0..1 | 636 final num _s; // Value from 0..1 |
| 645 final num _l; // Value from 0..1 | 637 final num _l; // Value from 0..1 |
| 646 final num _a; // Value from 0..1 | 638 final num _a; // Value from 0..1 |
| 647 | 639 |
| 648 /** | 640 /** |
| 649 * [hue] is a 0..1 fraction of 360 degrees (360 == 0). | 641 * [hue] is a 0..1 fraction of 360 degrees (360 == 0). |
| 650 * [saturation] is a 0..1 fraction (100% == 1). | 642 * [saturation] is a 0..1 fraction (100% == 1). |
| 651 * [lightness] is a 0..1 fraction (100% == 1). | 643 * [lightness] is a 0..1 fraction (100% == 1). |
| 652 * [alpha] is a 0..1 fraction, alpha blending between 0..1, 1 == 100% opaque. | 644 * [alpha] is a 0..1 fraction, alpha blending between 0..1, 1 == 100% opaque. |
| 653 */ | 645 */ |
| 654 Hsla(num hue, num saturation, num lightness, [num alpha]) : | 646 Hsla(num hue, num saturation, num lightness, [num alpha]) |
| 655 this._h = (hue == 1) ? 0 : Color._clamp(hue, 0, 1), | 647 : this._h = (hue == 1) ? 0 : Color._clamp(hue, 0, 1), |
| 656 this._s = Color._clamp(saturation, 0, 1), | 648 this._s = Color._clamp(saturation, 0, 1), |
| 657 this._l = Color._clamp(lightness, 0, 1), | 649 this._l = Color._clamp(lightness, 0, 1), |
| 658 this._a = (alpha != null) ? Color._clamp(alpha, 0, 1) : alpha; | 650 this._a = (alpha != null) ? Color._clamp(alpha, 0, 1) : alpha; |
| 659 | 651 |
| 660 factory Hsla.fromString(String hexValue) { | 652 factory Hsla.fromString(String hexValue) { |
| 661 Rgba rgba = new Color.css("#${Color._convertCssToArgb(hexValue)}").rgba; | 653 Rgba rgba = new Color.css("#${Color._convertCssToArgb(hexValue)}").rgba; |
| 662 return _createFromRgba(rgba.r, rgba.g, rgba.b, rgba.a); | 654 return _createFromRgba(rgba.r, rgba.g, rgba.b, rgba.a); |
| 663 } | 655 } |
| 664 | 656 |
| 665 factory Hsla.fromColor(Color color) { | 657 factory Hsla.fromColor(Color color) { |
| 666 Rgba rgba = color.rgba; | 658 Rgba rgba = color.rgba; |
| 667 return _createFromRgba(rgba.r, rgba.g, rgba.b, rgba.a); | 659 return _createFromRgba(rgba.r, rgba.g, rgba.b, rgba.a); |
| 668 } | 660 } |
| 669 | 661 |
| 670 factory Hsla.fromArgbValue(num value) { | 662 factory Hsla.fromArgbValue(num value) { |
| 671 num a = (value.toInt() & 0xff000000) >> 0x18; | 663 num a = (value.toInt() & 0xff000000) >> 0x18; |
| 672 int r = (value.toInt() & 0xff0000) >> 0x10; | 664 int r = (value.toInt() & 0xff0000) >> 0x10; |
| 673 int g = (value.toInt() & 0xff00) >> 8; | 665 int g = (value.toInt() & 0xff00) >> 8; |
| 674 int b = value.toInt() & 0xff; | 666 int b = value.toInt() & 0xff; |
| 675 | 667 |
| 676 // Convert alpha to 0..1 from (0..255). | 668 // Convert alpha to 0..1 from (0..255). |
| 677 if (a != null) { | 669 if (a != null) { |
| 678 a = double.parse((a / 255).toStringAsPrecision(2)); | 670 a = double.parse((a / 255).toStringAsPrecision(2)); |
| 679 } | 671 } |
| 680 | 672 |
| 681 return _createFromRgba(r, g, b, a); | 673 return _createFromRgba(r, g, b, a); |
| 682 } | 674 } |
| 683 | 675 |
| 684 factory Hsla.fromRgba(Rgba rgba) => | 676 factory Hsla.fromRgba(Rgba rgba) => |
| 685 _createFromRgba(rgba.r, rgba.g, rgba.b, rgba.a); | 677 _createFromRgba(rgba.r, rgba.g, rgba.b, rgba.a); |
| 686 | 678 |
| 687 static Hsla _createFromRgba(num r, num g, num b, num a) { | 679 static Hsla _createFromRgba(num r, num g, num b, num a) { |
| 688 // Convert RGB to hsl. | 680 // Convert RGB to hsl. |
| 689 // See site <http://easyrgb.com/index.php?X=MATH> for good documentation | 681 // See site <http://easyrgb.com/index.php?X=MATH> for good documentation |
| 690 // and color conversion routines. | 682 // and color conversion routines. |
| 691 r /= 255; | 683 r /= 255; |
| 692 g /= 255; | 684 g /= 255; |
| 693 b /= 255; | 685 b /= 255; |
| 694 | 686 |
| 695 // Hue, saturation and lightness. | 687 // Hue, saturation and lightness. |
| 696 num h; | 688 num h; |
| 697 num s; | 689 num s; |
| 698 num l; | 690 num l; |
| 699 | 691 |
| 700 num minRgb = math.min(r, math.min(g, b)); | 692 num minRgb = math.min(r, math.min(g, b)); |
| 701 num maxRgb = math.max(r, math.max(g, b)); | 693 num maxRgb = math.max(r, math.max(g, b)); |
| 702 l = (maxRgb + minRgb) / 2; | 694 l = (maxRgb + minRgb) / 2; |
| 703 if (l <= 0) { | 695 if (l <= 0) { |
| 704 return new Hsla(0, 0, l); // Black; | 696 return new Hsla(0, 0, l); // Black; |
| 705 } | 697 } |
| 706 | 698 |
| 707 num vm = maxRgb - minRgb; | 699 num vm = maxRgb - minRgb; |
| 708 s = vm; | 700 s = vm; |
| 709 if (s > 0) { | 701 if (s > 0) { |
| 710 s /= (l < 0.5) ? (maxRgb + minRgb) : (2 - maxRgb - minRgb); | 702 s /= (l < 0.5) ? (maxRgb + minRgb) : (2 - maxRgb - minRgb); |
| 711 } else { | 703 } else { |
| 712 return new Hsla(0, 0, l); // White | 704 return new Hsla(0, 0, l); // White |
| 713 } | 705 } |
| 714 | 706 |
| 715 num r2, g2, b2; | 707 num r2, g2, b2; |
| 716 r2 = (maxRgb - r) / vm; | 708 r2 = (maxRgb - r) / vm; |
| 717 g2 = (maxRgb - g) / vm; | 709 g2 = (maxRgb - g) / vm; |
| 718 b2 = (maxRgb - b) / vm; | 710 b2 = (maxRgb - b) / vm; |
| 719 if (r == maxRgb) { | 711 if (r == maxRgb) { |
| 720 h = (g == minRgb) ? 5.0 + b2 : 1 - g2; | 712 h = (g == minRgb) ? 5.0 + b2 : 1 - g2; |
| 721 } else if (g == maxRgb) { | 713 } else if (g == maxRgb) { |
| 722 h = (b == minRgb) ? 1 + r2 : 3 - b2; | 714 h = (b == minRgb) ? 1 + r2 : 3 - b2; |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 758 */ | 750 */ |
| 759 num get lightnessPercentage => (_l * 100).round(); | 751 num get lightnessPercentage => (_l * 100).round(); |
| 760 | 752 |
| 761 /** | 753 /** |
| 762 * Returns number as 0..1 | 754 * Returns number as 0..1 |
| 763 */ | 755 */ |
| 764 num get alpha => _a; | 756 num get alpha => _a; |
| 765 | 757 |
| 766 bool operator ==(other) => Color.equal(this, other); | 758 bool operator ==(other) => Color.equal(this, other); |
| 767 | 759 |
| 768 String get cssExpression => (_a == null) ? | 760 String get cssExpression => (_a == null) |
| 769 "hsl($hueDegrees,$saturationPercentage,$lightnessPercentage)" : | 761 ? "hsl($hueDegrees,$saturationPercentage,$lightnessPercentage)" |
| 770 "hsla($hueDegrees,$saturationPercentage,$lightnessPercentage,$_a)"; | 762 : "hsla($hueDegrees,$saturationPercentage,$lightnessPercentage,$_a)"; |
| 771 | 763 |
| 772 String toHexArgbString() => new Rgba.fromHsla(this).toHexArgbString(); | 764 String toHexArgbString() => new Rgba.fromHsla(this).toHexArgbString(); |
| 773 | 765 |
| 774 int get argbValue => Color.hexToInt(this.toHexArgbString()); | 766 int get argbValue => Color.hexToInt(this.toHexArgbString()); |
| 775 | 767 |
| 776 Color get color => new Color.createHsla(_h, _s, _l, _a); | 768 Color get color => new Color.createHsla(_h, _s, _l, _a); |
| 777 Rgba get rgba => new Rgba.fromHsla(this); | 769 Rgba get rgba => new Rgba.fromHsla(this); |
| 778 | 770 |
| 779 Hsla darker(num amount) => | 771 Hsla darker(num amount) => |
| 780 new Hsla.fromRgba(new Rgba.fromHsla(this).darker(amount)); | 772 new Hsla.fromRgba(new Rgba.fromHsla(this).darker(amount)); |
| 781 | 773 |
| 782 Hsla lighter(num amount) => | 774 Hsla lighter(num amount) => |
| 783 new Hsla.fromRgba(new Rgba.fromHsla(this).lighter(amount)); | 775 new Hsla.fromRgba(new Rgba.fromHsla(this).lighter(amount)); |
| 784 | 776 |
| 785 int get hashCode => toHexArgbString().hashCode; | 777 int get hashCode => toHexArgbString().hashCode; |
| 786 } | 778 } |
| 787 | 779 |
| 788 | |
| 789 /** X,Y position. */ | 780 /** X,Y position. */ |
| 790 class PointXY implements _StyleProperty { | 781 class PointXY implements _StyleProperty { |
| 791 final num x, y; | 782 final num x, y; |
| 792 const PointXY(this.x, this.y); | 783 const PointXY(this.x, this.y); |
| 793 | 784 |
| 794 String get cssExpression { | 785 String get cssExpression { |
| 795 // TODO(terry): TBD | 786 // TODO(terry): TBD |
| 796 } | 787 } |
| 797 } | 788 } |
| 798 | 789 |
| 799 | |
| 800 // TODO(terry): Implement style and color. | 790 // TODO(terry): Implement style and color. |
| 801 /** | 791 /** |
| 802 * Supports border for measuring with layout. | 792 * Supports border for measuring with layout. |
| 803 */ | 793 */ |
| 804 class Border implements _StyleProperty { | 794 class Border implements _StyleProperty { |
| 805 final int top, left, bottom, right; | 795 final int top, left, bottom, right; |
| 806 | 796 |
| 807 // TODO(terry): Just like CSS, 1-arg -> set all properties, 2-args -> top and | 797 // TODO(terry): Just like CSS, 1-arg -> set all properties, 2-args -> top and |
| 808 // bottom are first arg, left and right are second, 3-args, and | 798 // bottom are first arg, left and right are second, 3-args, and |
| 809 // 4-args -> tlbr or trbl. | 799 // 4-args -> tlbr or trbl. |
| 810 const Border([this.top, this.left, this.bottom, this.right]); | 800 const Border([this.top, this.left, this.bottom, this.right]); |
| 811 | 801 |
| 812 // TODO(terry): Consider using Size or width and height. | 802 // TODO(terry): Consider using Size or width and height. |
| 813 Border.uniform(num amount) : | 803 Border.uniform(num amount) |
| 814 top = amount, left = amount, bottom = amount, right = amount; | 804 : top = amount, |
| 805 left = amount, |
| 806 bottom = amount, |
| 807 right = amount; |
| 815 | 808 |
| 816 int get width => left + right; | 809 int get width => left + right; |
| 817 int get height => top + bottom; | 810 int get height => top + bottom; |
| 818 | 811 |
| 819 String get cssExpression { | 812 String get cssExpression { |
| 820 return (top == left && bottom == right && top == right) ? "${left}px" : | 813 return (top == left && bottom == right && top == right) |
| 821 "${top != null ? '$top' : '0'}px ${ | 814 ? "${left}px" |
| 815 : "${top != null ? '$top' : '0'}px ${ |
| 822 right != null ? '$right' : '0'}px ${ | 816 right != null ? '$right' : '0'}px ${ |
| 823 bottom != null ? '$bottom' : '0'}px ${ | 817 bottom != null ? '$bottom' : '0'}px ${ |
| 824 left != null ? '$left' : '0'}px"; | 818 left != null ? '$left' : '0'}px"; |
| 825 } | 819 } |
| 826 } | 820 } |
| 827 | 821 |
| 828 | |
| 829 /** Font style constants. */ | 822 /** Font style constants. */ |
| 830 class FontStyle { | 823 class FontStyle { |
| 831 /** Font style [normal] default. */ | 824 /** Font style [normal] default. */ |
| 832 static const String normal = "normal"; | 825 static const String normal = "normal"; |
| 833 /** | 826 /** |
| 834 * Font style [italic] use explicity crafted italic font otherwise inclined | 827 * Font style [italic] use explicity crafted italic font otherwise inclined |
| 835 * on the fly like oblique. | 828 * on the fly like oblique. |
| 836 */ | 829 */ |
| 837 static const String italic = "italic"; | 830 static const String italic = "italic"; |
| 838 /** | 831 /** |
| 839 * Font style [oblique] is rarely used. The normal style of a font is inclined | 832 * Font style [oblique] is rarely used. The normal style of a font is inclined |
| 840 * on the fly to the right by 8-12 degrees. | 833 * on the fly to the right by 8-12 degrees. |
| 841 */ | 834 */ |
| 842 static const String oblique = "oblique"; | 835 static const String oblique = "oblique"; |
| 843 } | 836 } |
| 844 | 837 |
| 845 | |
| 846 /** Font variant constants. */ | 838 /** Font variant constants. */ |
| 847 class FontVariant { | 839 class FontVariant { |
| 848 /** Font style [normal] default. */ | 840 /** Font style [normal] default. */ |
| 849 static const String normal = "normal"; | 841 static const String normal = "normal"; |
| 850 /** Font variant [smallCaps]. */ | 842 /** Font variant [smallCaps]. */ |
| 851 static const String smallCaps = "small-caps"; | 843 static const String smallCaps = "small-caps"; |
| 852 } | 844 } |
| 853 | 845 |
| 854 | |
| 855 /** Font weight constants values 100, 200, 300, 400, 500, 600, 700, 800, 900. */ | 846 /** Font weight constants values 100, 200, 300, 400, 500, 600, 700, 800, 900. */ |
| 856 class FontWeight { | 847 class FontWeight { |
| 857 /** Font weight normal [default] */ | 848 /** Font weight normal [default] */ |
| 858 static const int normal = 400; | 849 static const int normal = 400; |
| 859 /** Font weight bold */ | 850 /** Font weight bold */ |
| 860 static const int bold = 700; | 851 static const int bold = 700; |
| 861 | 852 |
| 862 static const int wt100 = 100; | 853 static const int wt100 = 100; |
| 863 static const int wt200 = 200; | 854 static const int wt200 = 200; |
| 864 static const int wt300 = 300; | 855 static const int wt300 = 300; |
| 865 static const int wt400 = 400; | 856 static const int wt400 = 400; |
| 866 static const int wt500 = 500; | 857 static const int wt500 = 500; |
| 867 static const int wt600 = 600; | 858 static const int wt600 = 600; |
| 868 static const int wt700 = 700; | 859 static const int wt700 = 700; |
| 869 static const int wt800 = 800; | 860 static const int wt800 = 800; |
| 870 static const int wt900 = 900; | 861 static const int wt900 = 900; |
| 871 } | 862 } |
| 872 | 863 |
| 873 | |
| 874 /** Generic font family names. */ | 864 /** Generic font family names. */ |
| 875 class FontGeneric { | 865 class FontGeneric { |
| 876 /** Generic family sans-serif font (w/o serifs). */ | 866 /** Generic family sans-serif font (w/o serifs). */ |
| 877 static const String sansSerif = "sans-serif"; | 867 static const String sansSerif = "sans-serif"; |
| 878 /** Generic family serif font. */ | 868 /** Generic family serif font. */ |
| 879 static const String serif = "serif"; | 869 static const String serif = "serif"; |
| 880 /** Generic family fixed-width font. */ | 870 /** Generic family fixed-width font. */ |
| 881 static const monospace = "monospace"; | 871 static const monospace = "monospace"; |
| 882 /** Generic family emulate handwriting font. */ | 872 /** Generic family emulate handwriting font. */ |
| 883 static const String cursive = "cursive"; | 873 static const String cursive = "cursive"; |
| 884 /** Generic family decorative font. */ | 874 /** Generic family decorative font. */ |
| 885 static const String fantasy = "fantasy"; | 875 static const String fantasy = "fantasy"; |
| 886 } | 876 } |
| 887 | 877 |
| 888 | |
| 889 /** | 878 /** |
| 890 * List of most common font families across different platforms. Use the | 879 * List of most common font families across different platforms. Use the |
| 891 * collection names in the Font class (e.g., Font.SANS_SERIF, Font.FONT_SERIF, | 880 * collection names in the Font class (e.g., Font.SANS_SERIF, Font.FONT_SERIF, |
| 892 * Font.MONOSPACE, Font.CURSIVE or Font.FANTASY). These work best on all | 881 * Font.MONOSPACE, Font.CURSIVE or Font.FANTASY). These work best on all |
| 893 * platforms using the fonts that best match availability on each platform. | 882 * platforms using the fonts that best match availability on each platform. |
| 894 * See <http://www.angelfire.com/al4/rcollins/style/fonts.html> for a good | 883 * See <http://www.angelfire.com/al4/rcollins/style/fonts.html> for a good |
| 895 * description of fonts available between platforms and browsers. | 884 * description of fonts available between platforms and browsers. |
| 896 */ | 885 */ |
| 897 class FontFamily { | 886 class FontFamily { |
| 898 /** Sans-Serif font for Windows similar to Helvetica on Mac bold/italic. */ | 887 /** Sans-Serif font for Windows similar to Helvetica on Mac bold/italic. */ |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 938 | 927 |
| 939 /** Fantasy font on most Mac/Windows/Linux platforms. */ | 928 /** Fantasy font on most Mac/Windows/Linux platforms. */ |
| 940 static const String impact = "impact"; | 929 static const String impact = "impact"; |
| 941 /** Fantasy font for Windows. */ | 930 /** Fantasy font for Windows. */ |
| 942 static const String webdings = "webdings"; | 931 static const String webdings = "webdings"; |
| 943 } | 932 } |
| 944 | 933 |
| 945 class LineHeight { | 934 class LineHeight { |
| 946 final num height; | 935 final num height; |
| 947 final bool inPixels; | 936 final bool inPixels; |
| 948 const LineHeight(this.height, {this.inPixels : true}); | 937 const LineHeight(this.height, {this.inPixels: true}); |
| 949 } | 938 } |
| 950 | 939 |
| 951 // TODO(terry): Support @font-face fule. | 940 // TODO(terry): Support @font-face fule. |
| 952 /** | 941 /** |
| 953 * Font style support for size, family, weight, style, variant, and lineheight. | 942 * Font style support for size, family, weight, style, variant, and lineheight. |
| 954 */ | 943 */ |
| 955 class Font implements _StyleProperty { | 944 class Font implements _StyleProperty { |
| 956 /** Collection of most common sans-serif fonts in order. */ | 945 /** Collection of most common sans-serif fonts in order. */ |
| 957 static const List<String> sansSerif = const [FontFamily.arial, | 946 static const List<String> sansSerif = const [ |
| 958 FontFamily.verdana, | 947 FontFamily.arial, |
| 959 FontFamily.geneva, | 948 FontFamily.verdana, |
| 960 FontFamily.helvetica, | 949 FontFamily.geneva, |
| 961 FontGeneric.sansSerif]; | 950 FontFamily.helvetica, |
| 951 FontGeneric.sansSerif |
| 952 ]; |
| 962 | 953 |
| 963 /** Collection of most common serif fonts in order. */ | 954 /** Collection of most common serif fonts in order. */ |
| 964 static const List<String> serif = const [FontFamily.georgia, | 955 static const List<String> serif = const [ |
| 965 FontFamily.timesNewRoman, | 956 FontFamily.georgia, |
| 966 FontFamily.times, | 957 FontFamily.timesNewRoman, |
| 967 FontGeneric.serif]; | 958 FontFamily.times, |
| 959 FontGeneric.serif |
| 960 ]; |
| 968 /** Collection of most common monospace fonts in order. */ | 961 /** Collection of most common monospace fonts in order. */ |
| 969 static const List<String> monospace = const [FontFamily.courierNew, | 962 static const List<String> monospace = const [ |
| 970 FontFamily.courier, | 963 FontFamily.courierNew, |
| 971 FontGeneric.monospace]; | 964 FontFamily.courier, |
| 965 FontGeneric.monospace |
| 966 ]; |
| 972 /** Collection of most common cursive fonts in order. */ | 967 /** Collection of most common cursive fonts in order. */ |
| 973 static const List<String> cursive = const [FontFamily.textile, | 968 static const List<String> cursive = const [ |
| 974 FontFamily.appleChancery, | 969 FontFamily.textile, |
| 975 FontFamily.zaphChancery, | 970 FontFamily.appleChancery, |
| 976 FontGeneric.fantasy]; | 971 FontFamily.zaphChancery, |
| 972 FontGeneric.fantasy |
| 973 ]; |
| 977 /** Collection of most common fantasy fonts in order. */ | 974 /** Collection of most common fantasy fonts in order. */ |
| 978 static const List<String> fantasy = const [FontFamily.comicSansMs, | 975 static const List<String> fantasy = const [ |
| 979 FontFamily.impact, | 976 FontFamily.comicSansMs, |
| 980 FontFamily.webdings, | 977 FontFamily.impact, |
| 981 FontGeneric.fantasy]; | 978 FontFamily.webdings, |
| 979 FontGeneric.fantasy |
| 980 ]; |
| 982 | 981 |
| 983 // TODO(terry): Should support the values xx-small, small, large, xx-large, | 982 // TODO(terry): Should support the values xx-small, small, large, xx-large, |
| 984 // etc. (mapped to a pixel sized font)? | 983 // etc. (mapped to a pixel sized font)? |
| 985 /** Font size in pixels. */ | 984 /** Font size in pixels. */ |
| 986 final num size; | 985 final num size; |
| 987 | 986 |
| 988 // TODO(terry): _family should be an immutable list, wrapper class to do this | 987 // TODO(terry): _family should be an immutable list, wrapper class to do this |
| 989 // should exist in Dart. | 988 // should exist in Dart. |
| 990 /** | 989 /** |
| 991 * Family specifies a list of fonts, the browser will sequentially select the | 990 * Family specifies a list of fonts, the browser will sequentially select the |
| (...skipping 29 matching lines...) Expand all Loading... |
| 1021 // height. Classic typography suggest the ratio be 1.5. See | 1020 // height. Classic typography suggest the ratio be 1.5. See |
| 1022 // <http://www.pearsonified.com/2011/12/golden-ratio-typography.php> and | 1021 // <http://www.pearsonified.com/2011/12/golden-ratio-typography.php> and |
| 1023 // <http://meyerweb.com/eric/thoughts/2008/05/06/line-height-abnormal/>. | 1022 // <http://meyerweb.com/eric/thoughts/2008/05/06/line-height-abnormal/>. |
| 1024 /** | 1023 /** |
| 1025 * Create a font using [size] of font in pixels, [family] name of font(s) | 1024 * Create a font using [size] of font in pixels, [family] name of font(s) |
| 1026 * using [FontFamily], [style] of the font using [FontStyle], [variant] using | 1025 * using [FontFamily], [style] of the font using [FontStyle], [variant] using |
| 1027 * [FontVariant], and [lineHeight] extra space (leading) around the font in | 1026 * [FontVariant], and [lineHeight] extra space (leading) around the font in |
| 1028 * pixels, if not specified it's 1.2 the font size. | 1027 * pixels, if not specified it's 1.2 the font size. |
| 1029 */ | 1028 */ |
| 1030 const Font({this.size, this.family, this.weight, this.style, this.variant, | 1029 const Font({this.size, this.family, this.weight, this.style, this.variant, |
| 1031 this.lineHeight}); | 1030 this.lineHeight}); |
| 1032 | 1031 |
| 1033 /** | 1032 /** |
| 1034 * Merge the two fonts and return the result. See [Style.merge] for | 1033 * Merge the two fonts and return the result. See [Style.merge] for |
| 1035 * more information. | 1034 * more information. |
| 1036 */ | 1035 */ |
| 1037 factory Font.merge(Font a, Font b) { | 1036 factory Font.merge(Font a, Font b) { |
| 1038 if (a == null) return b; | 1037 if (a == null) return b; |
| 1039 if (b == null) return a; | 1038 if (b == null) return a; |
| 1040 return new Font._merge(a, b); | 1039 return new Font._merge(a, b); |
| 1041 } | 1040 } |
| 1042 | 1041 |
| 1043 Font._merge(Font a, Font b) | 1042 Font._merge(Font a, Font b) |
| 1044 : size = _mergeVal(a.size, b.size), | 1043 : size = _mergeVal(a.size, b.size), |
| 1045 family = _mergeVal(a.family, b.family), | 1044 family = _mergeVal(a.family, b.family), |
| 1046 weight = _mergeVal(a.weight, b.weight), | 1045 weight = _mergeVal(a.weight, b.weight), |
| 1047 style = _mergeVal(a.style, b.style), | 1046 style = _mergeVal(a.style, b.style), |
| 1048 variant = _mergeVal(a.variant, b.variant), | 1047 variant = _mergeVal(a.variant, b.variant), |
| 1049 lineHeight = _mergeVal(a.lineHeight, b.lineHeight); | 1048 lineHeight = _mergeVal(a.lineHeight, b.lineHeight); |
| 1050 | 1049 |
| 1051 /** | 1050 /** |
| 1052 * Shorthand CSS format for font is: | 1051 * Shorthand CSS format for font is: |
| 1053 * | 1052 * |
| 1054 * font-style font-variant font-weight font-size/line-height font-family | 1053 * font-style font-variant font-weight font-size/line-height font-family |
| 1055 * | 1054 * |
| 1056 * The font-size and font-family values are required. If any of the other | 1055 * The font-size and font-family values are required. If any of the other |
| 1057 * values are missing the default value is used. | 1056 * values are missing the default value is used. |
| 1058 */ | 1057 */ |
| 1059 String get cssExpression { | 1058 String get cssExpression { |
| 1060 // TODO(jimhug): include variant, style, other options | 1059 // TODO(jimhug): include variant, style, other options |
| 1061 if (weight != null) { | 1060 if (weight != null) { |
| 1062 // TODO(jacobr): is this really correct for lineHeight? | 1061 // TODO(jacobr): is this really correct for lineHeight? |
| 1063 if (lineHeight != null) { | 1062 if (lineHeight != null) { |
| 1064 return "$weight ${size}px/$lineHeightInPixels $_fontsAsString"; | 1063 return "$weight ${size}px/$lineHeightInPixels $_fontsAsString"; |
| 1065 } | 1064 } |
| 1066 return '$weight ${size}px $_fontsAsString'; | 1065 return '$weight ${size}px $_fontsAsString'; |
| 1067 } | 1066 } |
| 1068 | 1067 |
| 1069 return '${size}px $_fontsAsString'; | 1068 return '${size}px $_fontsAsString'; |
| 1070 } | 1069 } |
| 1071 | 1070 |
| 1072 Font scale(num ratio) => | 1071 Font scale(num ratio) => new Font( |
| 1073 new Font(size: size * ratio, family: family, weight: weight, style: style, | 1072 size: size * ratio, |
| 1074 variant: variant); | 1073 family: family, |
| 1074 weight: weight, |
| 1075 style: style, |
| 1076 variant: variant); |
| 1075 | 1077 |
| 1076 /** | 1078 /** |
| 1077 * The lineHeight, provides an indirect means to specify the leading. The | 1079 * The lineHeight, provides an indirect means to specify the leading. The |
| 1078 * leading is the difference between the font-size height and the (used) | 1080 * leading is the difference between the font-size height and the (used) |
| 1079 * value of line height in pixels. If lineHeight is not specified it's | 1081 * value of line height in pixels. If lineHeight is not specified it's |
| 1080 * automatically computed as 1.2 of the font size. Firefox is 1.2, Safari is | 1082 * automatically computed as 1.2 of the font size. Firefox is 1.2, Safari is |
| 1081 * ~1.2, and CSS suggest a ration from 1 to 1.2 of the font-size when | 1083 * ~1.2, and CSS suggest a ration from 1 to 1.2 of the font-size when |
| 1082 * computing line-height. The Font class constructor has the computation for | 1084 * computing line-height. The Font class constructor has the computation for |
| 1083 * _lineHeight. | 1085 * _lineHeight. |
| 1084 */ | 1086 */ |
| (...skipping 10 matching lines...) Expand all Loading... |
| 1095 } | 1097 } |
| 1096 | 1098 |
| 1097 int get hashCode { | 1099 int get hashCode { |
| 1098 // TODO(jimhug): Lot's of potential collisions here. List of fonts, etc. | 1100 // TODO(jimhug): Lot's of potential collisions here. List of fonts, etc. |
| 1099 return size.toInt() % family[0].hashCode; | 1101 return size.toInt() % family[0].hashCode; |
| 1100 } | 1102 } |
| 1101 | 1103 |
| 1102 bool operator ==(other) { | 1104 bool operator ==(other) { |
| 1103 if (other is! Font) return false; | 1105 if (other is! Font) return false; |
| 1104 Font o = other; | 1106 Font o = other; |
| 1105 return o.size == size && o.family == family && o.weight == weight && | 1107 return o.size == size && |
| 1106 o.lineHeight == lineHeight && o.style == style && o.variant == variant; | 1108 o.family == family && |
| 1109 o.weight == weight && |
| 1110 o.lineHeight == lineHeight && |
| 1111 o.style == style && |
| 1112 o.variant == variant; |
| 1107 } | 1113 } |
| 1108 | 1114 |
| 1109 // TODO(terry): This is fragile should probably just iterate through the list | 1115 // TODO(terry): This is fragile should probably just iterate through the list |
| 1110 // of fonts construction the font-family string. | 1116 // of fonts construction the font-family string. |
| 1111 /** Return fonts as a comma seperated list sans the square brackets. */ | 1117 /** Return fonts as a comma seperated list sans the square brackets. */ |
| 1112 String get _fontsAsString { | 1118 String get _fontsAsString { |
| 1113 String fonts = family.toString(); | 1119 String fonts = family.toString(); |
| 1114 return fonts.length > 2 ? fonts.substring(1, fonts.length - 1) : ""; | 1120 return fonts.length > 2 ? fonts.substring(1, fonts.length - 1) : ""; |
| 1115 } | 1121 } |
| 1116 } | 1122 } |
| (...skipping 28 matching lines...) Expand all Loading... |
| 1145 */ | 1151 */ |
| 1146 const BoxEdge([this.left, this.top, this.right, this.bottom]); | 1152 const BoxEdge([this.left, this.top, this.right, this.bottom]); |
| 1147 | 1153 |
| 1148 /** | 1154 /** |
| 1149 * Creates a box edge with the specified [top], [right], [bottom], and | 1155 * Creates a box edge with the specified [top], [right], [bottom], and |
| 1150 * [left] width. This matches the typical CSS order: | 1156 * [left] width. This matches the typical CSS order: |
| 1151 * <https://developer.mozilla.org/en/CSS/margin> | 1157 * <https://developer.mozilla.org/en/CSS/margin> |
| 1152 * <https://developer.mozilla.org/en/CSS/border-width> | 1158 * <https://developer.mozilla.org/en/CSS/border-width> |
| 1153 * <https://developer.mozilla.org/en/CSS/padding>. | 1159 * <https://developer.mozilla.org/en/CSS/padding>. |
| 1154 */ | 1160 */ |
| 1155 const BoxEdge.clockwiseFromTop(this.top, this.right, this.bottom, this.left); | 1161 const BoxEdge.clockwiseFromTop(this.top, this.right, this.bottom, this.left); |
| 1156 | 1162 |
| 1157 /** | 1163 /** |
| 1158 * This is a helper to creates a box edge with the same [left], [top] | 1164 * This is a helper to creates a box edge with the same [left], [top] |
| 1159 * [right], and [bottom] widths. | 1165 * [right], and [bottom] widths. |
| 1160 */ | 1166 */ |
| 1161 const BoxEdge.uniform(num size) | 1167 const BoxEdge.uniform(num size) |
| 1162 : top = size, left = size, bottom = size, right = size; | 1168 : top = size, |
| 1169 left = size, |
| 1170 bottom = size, |
| 1171 right = size; |
| 1163 | 1172 |
| 1164 /** | 1173 /** |
| 1165 * Takes a possibly null box edge, with possibly null metrics, and fills | 1174 * Takes a possibly null box edge, with possibly null metrics, and fills |
| 1166 * them in with 0 instead. | 1175 * them in with 0 instead. |
| 1167 */ | 1176 */ |
| 1168 factory BoxEdge.nonNull(BoxEdge other) { | 1177 factory BoxEdge.nonNull(BoxEdge other) { |
| 1169 if (other == null) return const BoxEdge(0, 0, 0, 0); | 1178 if (other == null) return const BoxEdge(0, 0, 0, 0); |
| 1170 num left = other.left; | 1179 num left = other.left; |
| 1171 num top = other.top; | 1180 num top = other.top; |
| 1172 num right = other.right; | 1181 num right = other.right; |
| (...skipping 22 matching lines...) Expand all Loading... |
| 1195 * Merge the two box edge sizes and return the result. See [Style.merge] for | 1204 * Merge the two box edge sizes and return the result. See [Style.merge] for |
| 1196 * more information. | 1205 * more information. |
| 1197 */ | 1206 */ |
| 1198 factory BoxEdge.merge(BoxEdge x, BoxEdge y) { | 1207 factory BoxEdge.merge(BoxEdge x, BoxEdge y) { |
| 1199 if (x == null) return y; | 1208 if (x == null) return y; |
| 1200 if (y == null) return x; | 1209 if (y == null) return x; |
| 1201 return new BoxEdge._merge(x, y); | 1210 return new BoxEdge._merge(x, y); |
| 1202 } | 1211 } |
| 1203 | 1212 |
| 1204 BoxEdge._merge(BoxEdge x, BoxEdge y) | 1213 BoxEdge._merge(BoxEdge x, BoxEdge y) |
| 1205 : left = _mergeVal(x.left, y.left), | 1214 : left = _mergeVal(x.left, y.left), |
| 1206 top = _mergeVal(x.top, y.top), | 1215 top = _mergeVal(x.top, y.top), |
| 1207 right = _mergeVal(x.right, y.right), | 1216 right = _mergeVal(x.right, y.right), |
| 1208 bottom = _mergeVal(x.bottom, y.bottom); | 1217 bottom = _mergeVal(x.bottom, y.bottom); |
| 1209 | 1218 |
| 1210 /** | 1219 /** |
| 1211 * The total size of the horizontal edges. Equal to [left] + [right], where | 1220 * The total size of the horizontal edges. Equal to [left] + [right], where |
| 1212 * null is interpreted as 0px. | 1221 * null is interpreted as 0px. |
| 1213 */ | 1222 */ |
| 1214 num get width => (left != null ? left : 0) + (right != null ? right : 0); | 1223 num get width => (left != null ? left : 0) + (right != null ? right : 0); |
| 1215 | 1224 |
| 1216 /** | 1225 /** |
| 1217 * The total size of the vertical edges. Equal to [top] + [bottom], where | 1226 * The total size of the vertical edges. Equal to [top] + [bottom], where |
| 1218 * null is interpreted as 0px. | 1227 * null is interpreted as 0px. |
| 1219 */ | 1228 */ |
| 1220 num get height => (top != null ? top : 0) + (bottom != null ? bottom : 0); | 1229 num get height => (top != null ? top : 0) + (bottom != null ? bottom : 0); |
| 1221 } | 1230 } |
| 1222 | 1231 |
| 1223 _mergeVal(x, y) => y != null ? y : x; | 1232 _mergeVal(x, y) => y != null ? y : x; |
| OLD | NEW |