| OLD | NEW |
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 import 'dart:sky' as sky; | 5 import 'dart:sky' as sky; |
| 6 import 'box.dart'; | 6 import 'box.dart'; |
| 7 import 'object.dart'; | 7 import 'object.dart'; |
| 8 | 8 |
| 9 class RenderInline extends RenderObject { | 9 class RenderInline extends RenderObject { |
| 10 RenderInline(this.data); | 10 RenderInline(this.data); |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 61 int get hashCode { | 61 int get hashCode { |
| 62 // Use Quiver: https://github.com/domokit/mojo/issues/236 | 62 // Use Quiver: https://github.com/domokit/mojo/issues/236 |
| 63 int value = 373; | 63 int value = 373; |
| 64 value = 37 * value + color.hashCode; | 64 value = 37 * value + color.hashCode; |
| 65 value = 37 * value + fontSize.hashCode; | 65 value = 37 * value + fontSize.hashCode; |
| 66 value = 37 * value + fontWeight.hashCode; | 66 value = 37 * value + fontWeight.hashCode; |
| 67 value = 37 * value + textAlign.hashCode; | 67 value = 37 * value + textAlign.hashCode; |
| 68 return value; | 68 return value; |
| 69 } | 69 } |
| 70 | 70 |
| 71 void _applyToCSSStyle(CSSStyleDeclaration cssStyle) { |
| 72 if (color != null) { |
| 73 cssStyle['color'] = 'rgba(${color.red}, ${color.green}, ${color.blue}, ${c
olor.alpha / 255.0})'; |
| 74 } |
| 75 if (fontSize != null) { |
| 76 cssStyle['font-size'] = "${fontSize}px"; |
| 77 } |
| 78 if (fontWeight != null) { |
| 79 cssStyle['font-weight'] = const { |
| 80 FontWeight.light: '300', |
| 81 FontWeight.regular: '400', |
| 82 FontWeight.medium: '500', |
| 83 }[fontWeight]; |
| 84 } |
| 85 if (textAlign != null) { |
| 86 cssStyle['text-align'] = const { |
| 87 TextAlign.left: 'left', |
| 88 TextAlign.right: 'right', |
| 89 TextAlign.center: 'center', |
| 90 }[textAlign]; |
| 91 } |
| 92 } |
| 93 |
| 71 String toString([String prefix = '']) { | 94 String toString([String prefix = '']) { |
| 72 List<String> result = []; | 95 List<String> result = []; |
| 73 if (color != null) | 96 if (color != null) |
| 74 result.add('${prefix}color: $color'); | 97 result.add('${prefix}color: $color'); |
| 75 if (fontSize != null) | 98 if (fontSize != null) |
| 76 result.add('${prefix}fontSize: $fontSize'); | 99 result.add('${prefix}fontSize: $fontSize'); |
| 77 if (fontWeight != null) | 100 if (fontWeight != null) |
| 78 result.add('${prefix}fontWeight: fontWeight'); | 101 result.add('${prefix}fontWeight: $fontWeight'); |
| 79 if (textAlign != null) | 102 if (textAlign != null) |
| 80 result.add('${prefix}textAlign: textAlign'); | 103 result.add('${prefix}textAlign: $textAlign'); |
| 81 if (result.isEmpty) | 104 if (result.isEmpty) |
| 82 return '${prefix}<no style specified>'; | 105 return '${prefix}<no style specified>'; |
| 83 return result.join('\n'); | 106 return result.join('\n'); |
| 84 } | 107 } |
| 85 } | 108 } |
| 86 | 109 |
| 110 class TextNode { |
| 111 const TextStyle(this.style); |
| 112 |
| 113 final TextStyle style; |
| 114 |
| 115 Node _toDOM(); |
| 116 } |
| 117 |
| 118 class StyledText extends TextNode { |
| 119 const StyledText(this.text, { TextStyle style }) : super(style); |
| 120 |
| 121 final String text; |
| 122 |
| 123 Node _toDOM(Document owner) { |
| 124 Node node = owner.createText(text); |
| 125 if (style != null) { |
| 126 Element wrapper = owner.createElement('t'); |
| 127 style._applyToCSSStyle(wrapper.style); |
| 128 wrapper.appendChild(node); |
| 129 node = wrapper; |
| 130 } |
| 131 return node; |
| 132 } |
| 133 } |
| 134 |
| 135 class TextFragment extends TextNode { |
| 136 const StyledText(this.text, { TextStyle style }) : super(style); |
| 137 |
| 138 final List<TextNode> _children; |
| 139 |
| 140 List<TextNode> get children => new UnmodifiableListView<TextNode>(_children); |
| 141 |
| 142 Node _toDOM() { |
| 143 Element wrapper = owner.createElement('f'); |
| 144 if (style) |
| 145 style._applyToCSSStyle(wrapper.style); |
| 146 for (TextNode child in children) |
| 147 wrapper.appendChild(child._toDOM()); |
| 148 return wrapper; |
| 149 } |
| 150 } |
| 151 |
| 87 // Unfortunately, using full precision floating point here causes bad layouts | 152 // Unfortunately, using full precision floating point here causes bad layouts |
| 88 // because floating point math isn't associative. If we add and subtract | 153 // because floating point math isn't associative. If we add and subtract |
| 89 // padding, for example, we'll get different values when we estimate sizes and | 154 // padding, for example, we'll get different values when we estimate sizes and |
| 90 // when we actually compute layout because the operations will end up associated | 155 // when we actually compute layout because the operations will end up associated |
| 91 // differently. To work around this problem for now, we round fractional pixel | 156 // differently. To work around this problem for now, we round fractional pixel |
| 92 // values up to the nearest whole pixel value. The right long-term fix is to do | 157 // values up to the nearest whole pixel value. The right long-term fix is to do |
| 93 // layout using fixed precision arithmetic. | 158 // layout using fixed precision arithmetic. |
| 94 double _applyFloatingPointHack(double layoutValue) { | 159 double _applyFloatingPointHack(double layoutValue) { |
| 95 return layoutValue.ceilToDouble(); | 160 return layoutValue.ceilToDouble(); |
| 96 } | 161 } |
| 97 | 162 |
| 98 class RenderParagraph extends RenderBox { | 163 class RenderParagraph extends RenderBox { |
| 99 | 164 |
| 100 RenderParagraph({ | 165 RenderParagraph({ |
| 101 String text, | 166 TextNode node; |
| 102 Color color, | |
| 103 TextStyle style | |
| 104 }) : _style = style { | 167 }) : _style = style { |
| 105 _layoutRoot.rootElement = _document.createElement('p'); | 168 _layoutRoot.rootElement = _document.createElement('p'); |
| 106 this.text = text; | 169 this.text = text; |
| 107 } | 170 } |
| 108 | 171 |
| 109 final sky.Document _document = new sky.Document(); | 172 final sky.Document _document = new sky.Document(); |
| 110 final sky.LayoutRoot _layoutRoot = new sky.LayoutRoot(); | 173 final sky.LayoutRoot _layoutRoot = new sky.LayoutRoot(); |
| 111 | 174 |
| 112 String get text => (_layoutRoot.rootElement.firstChild as sky.Text).data; | 175 String get text => (_layoutRoot.rootElement.firstChild as sky.Text).data; |
| 113 void set text (String value) { | 176 void set text (String value) { |
| 114 _layoutRoot.rootElement.setChild(_document.createText(value)); | 177 _layoutRoot.rootElement.setChild(_document.createText(value)); |
| 115 markNeedsLayout(); | 178 markNeedsLayout(); |
| 116 } | 179 } |
| 117 | 180 |
| 118 TextStyle _style; | 181 TextNode _style; |
| 119 TextStyle get style => _style; | 182 TextNode get style => _style; |
| 120 void set style (TextStyle value) { | 183 void set style (TextStyle value) { |
| 121 if (_style != value) { | 184 if (_style != value) { |
| 122 // TODO(hansmuller): decide if a new layout or paint is needed | 185 // TODO(hansmuller): decide if a new layout or paint is needed |
| 123 markNeedsLayout(); | 186 markNeedsLayout(); |
| 124 _style = value; | 187 _style = value; |
| 125 } | 188 } |
| 126 } | 189 } |
| 127 | 190 |
| 128 BoxConstraints _constraintsForCurrentLayout; | 191 BoxConstraints _constraintsForCurrentLayout; |
| 129 | 192 |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 176 // will destroy state inside the layout root. If that happens, we need to | 239 // will destroy state inside the layout root. If that happens, we need to |
| 177 // get back the correct state by calling _layout again. | 240 // get back the correct state by calling _layout again. |
| 178 // | 241 // |
| 179 // TODO(abarth): Make computing the min/max intrinsic width/height a | 242 // TODO(abarth): Make computing the min/max intrinsic width/height a |
| 180 // non-destructive operation. | 243 // non-destructive operation. |
| 181 if (_constraintsForCurrentLayout != constraints && constraints != null) | 244 if (_constraintsForCurrentLayout != constraints && constraints != null) |
| 182 _layout(constraints); | 245 _layout(constraints); |
| 183 | 246 |
| 184 if (style != null) { | 247 if (style != null) { |
| 185 var cssStyle = _layoutRoot.rootElement.style; | 248 var cssStyle = _layoutRoot.rootElement.style; |
| 186 if (style.color != null) { | |
| 187 Color c = style.color; | |
| 188 cssStyle['color'] = | |
| 189 'rgba(${c.red}, ${c.green}, ${c.blue}, ${c.alpha / 255.0})'; | |
| 190 } | |
| 191 if (style.fontSize != null) { | |
| 192 cssStyle['font-size'] = "${style.fontSize}px"; | |
| 193 } | |
| 194 if (style.fontWeight != null) { | |
| 195 cssStyle['font-weight'] = const { | |
| 196 FontWeight.light: '300', | |
| 197 FontWeight.regular: '400', | |
| 198 FontWeight.medium: '500', | |
| 199 }[style.fontWeight]; | |
| 200 } | |
| 201 if (style.textAlign != null) { | |
| 202 cssStyle['text-align'] = const { | |
| 203 TextAlign.left: 'left', | |
| 204 TextAlign.right: 'right', | |
| 205 TextAlign.center: 'center', | |
| 206 }[style.textAlign]; | |
| 207 } | |
| 208 } | 249 } |
| 209 _layoutRoot.paint(canvas); | 250 _layoutRoot.paint(canvas); |
| 210 } | 251 } |
| 211 | 252 |
| 212 // we should probably expose a way to do precise (inter-glpyh) hit testing | 253 // we should probably expose a way to do precise (inter-glpyh) hit testing |
| 213 | 254 |
| 214 String debugDescribeSettings(String prefix) => '${super.debugDescribeSettings(
prefix)}${prefix}style:\n${style.toString("$prefix ")}\n${prefix}text: ${text}\
n'; | 255 String debugDescribeSettings(String prefix) => '${super.debugDescribeSettings(
prefix)}${prefix}style:\n${style.toString("$prefix ")}\n${prefix}text: ${text}\
n'; |
| 215 } | 256 } |
| OLD | NEW |