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 |