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