Skip to content

Commit 9073fd2

Browse files
committed
Refine font-size implementation, add support for line-height and text-shadow
1 parent 26488c6 commit 9073fd2

File tree

2 files changed

+135
-32
lines changed

2 files changed

+135
-32
lines changed

lib/src/css_parser.dart

Lines changed: 95 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@ Style declarationsToStyle(Map<String, List<css.Expression>> declarations) {
2020
case 'display':
2121
style.display = ExpressionMapping.expressionToDisplay(value.first);
2222
break;
23+
case 'line-height':
24+
style.lineHeight = ExpressionMapping.expressionToLineHeight(value.first);
25+
break;
2326
case 'font-family':
2427
style.fontFamily = ExpressionMapping.expressionToFontFamily(value.first);
2528
break;
@@ -38,6 +41,9 @@ Style declarationsToStyle(Map<String, List<css.Expression>> declarations) {
3841
case 'text-align':
3942
style.textAlign = ExpressionMapping.expressionToTextAlign(value.first);
4043
break;
44+
case 'text-shadow':
45+
style.textShadow = ExpressionMapping.expressionToTextShadow(value);
46+
break;
4147
}
4248
});
4349
return style;
@@ -151,6 +157,8 @@ class ExpressionMapping {
151157
return FontSize.em(double.tryParse(value.text));
152158
} else if (value is css.RemTerm) {
153159
return FontSize.rem(double.tryParse(value.text));
160+
} else if (value is css.LengthTerm) {
161+
return FontSize(double.tryParse(value.text.replaceAll(new RegExp(r'\s+(\d+\.\d+)\s+'), '')), "");
154162
} else if (value is css.LiteralTerm) {
155163
switch (value.text) {
156164
case "xx-small":
@@ -168,7 +176,6 @@ class ExpressionMapping {
168176
case "xx-large":
169177
return FontSize.xxLarge;
170178
}
171-
return FontSize(double.tryParse(value.text.replaceAll(new RegExp(r'\s+(\d+\.\d+)\s+'), '')), "");
172179
}
173180
return null;
174181
}
@@ -226,6 +233,92 @@ class ExpressionMapping {
226233
return null;
227234
}
228235

236+
static LineHeight expressionToLineHeight(css.Expression value) {
237+
if (value is css.NumberTerm) {
238+
return LineHeight.number(double.tryParse(value.text));
239+
} else if (value is css.PercentageTerm) {
240+
return LineHeight.percent(double.tryParse(value.text));
241+
} else if (value is css.EmTerm) {
242+
return LineHeight.em(double.tryParse(value.text));
243+
} else if (value is css.RemTerm) {
244+
return LineHeight.rem(double.tryParse(value.text));
245+
} else if (value is css.LengthTerm) {
246+
return LineHeight(double.tryParse(value.text.replaceAll(new RegExp(r'\s+(\d+\.\d+)\s+'), '')), "length");
247+
}
248+
return LineHeight.normal;
249+
}
250+
251+
static TextAlign expressionToTextAlign(css.Expression value) {
252+
if (value is css.LiteralTerm) {
253+
switch(value.text) {
254+
case "center":
255+
return TextAlign.center;
256+
case "left":
257+
return TextAlign.left;
258+
case "right":
259+
return TextAlign.right;
260+
case "justify":
261+
return TextAlign.justify;
262+
case "end":
263+
return TextAlign.end;
264+
case "start":
265+
return TextAlign.start;
266+
}
267+
}
268+
return TextAlign.start;
269+
}
270+
271+
static List<Shadow> expressionToTextShadow(List<css.Expression> value) {
272+
List<Shadow> shadow = [];
273+
List<int> indices = [];
274+
List<List<css.Expression>> valueList = [];
275+
for (css.Expression e in value) {
276+
if (e is css.OperatorComma) {
277+
indices.add(value.indexOf(e));
278+
}
279+
}
280+
indices.add(value.length);
281+
int previousIndex = 0;
282+
for (int i in indices) {
283+
valueList.add(value.sublist(previousIndex, i));
284+
previousIndex = i + 1;
285+
}
286+
for (List<css.Expression> list in valueList) {
287+
css.Expression exp = list[0];
288+
css.Expression exp2 = list[1];
289+
css.LiteralTerm exp3 = list.length > 2 ? list[2] : null;
290+
css.LiteralTerm exp4 = list.length > 3 ? list[3] : null;
291+
RegExp nonNumberRegex = RegExp(r'\s+(\d+\.\d+)\s+');
292+
if (exp is css.LiteralTerm && exp2 is css.LiteralTerm) {
293+
if (exp3 != null && (exp3 is css.HexColorTerm || exp3 is css.FunctionTerm)) {
294+
shadow.add(Shadow(
295+
color: expressionToColor(exp3),
296+
offset: Offset(double.tryParse(exp.text.replaceAll(nonNumberRegex, '')), double.tryParse(exp2.text.replaceAll(nonNumberRegex, '')))
297+
));
298+
} else if (exp3 != null && exp3 is css.LiteralTerm) {
299+
if (exp4 != null && (exp4 is css.HexColorTerm || exp4 is css.FunctionTerm)) {
300+
shadow.add(Shadow(
301+
color: expressionToColor(exp4),
302+
offset: Offset(double.tryParse(exp.text.replaceAll(nonNumberRegex, '')), double.tryParse(exp2.text.replaceAll(nonNumberRegex, ''))),
303+
blurRadius: double.tryParse(exp3.text.replaceAll(nonNumberRegex, ''))
304+
));
305+
} else {
306+
shadow.add(Shadow(
307+
offset: Offset(double.tryParse(exp.text.replaceAll(nonNumberRegex, '')), double.tryParse(exp2.text.replaceAll(nonNumberRegex, ''))),
308+
blurRadius: double.tryParse(exp3.text.replaceAll(nonNumberRegex, ''))
309+
));
310+
}
311+
} else {
312+
shadow.add(Shadow(
313+
offset: Offset(double.tryParse(exp.text.replaceAll(nonNumberRegex, '')), double.tryParse(exp2.text.replaceAll(nonNumberRegex, '')))
314+
));
315+
}
316+
}
317+
}
318+
shadow.toSet().toList();
319+
return shadow;
320+
}
321+
229322
static Color stringToColor(String _text) {
230323
var text = _text.replaceFirst('#', '');
231324
if (text.length == 3)
@@ -244,7 +337,7 @@ class ExpressionMapping {
244337
final rgbaText = text.replaceAll(')', '').replaceAll(' ', '');
245338
try {
246339
final rgbaValues =
247-
rgbaText.split(',').map((value) => double.parse(value)).toList();
340+
rgbaText.split(',').map((value) => double.parse(value)).toList();
248341
if (rgbaValues.length == 4) {
249342
return Color.fromRGBO(
250343
rgbaValues[0].toInt(),
@@ -265,24 +358,4 @@ class ExpressionMapping {
265358
return null;
266359
}
267360
}
268-
269-
static TextAlign expressionToTextAlign(css.Expression value) {
270-
if (value is css.LiteralTerm) {
271-
switch(value.text) {
272-
case "center":
273-
return TextAlign.center;
274-
case "left":
275-
return TextAlign.left;
276-
case "right":
277-
return TextAlign.right;
278-
case "justify":
279-
return TextAlign.justify;
280-
case "end":
281-
return TextAlign.end;
282-
case "start":
283-
return TextAlign.start;
284-
}
285-
}
286-
return TextAlign.start;
287-
}
288361
}

lib/style.dart

Lines changed: 40 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,7 @@ class Style {
166166
///
167167
/// Inherited: no,
168168
/// Default: Unspecified (null),
169-
double lineHeight;
169+
LineHeight lineHeight;
170170

171171
//TODO modify these to match CSS styles
172172
String before;
@@ -230,7 +230,7 @@ class Style {
230230
letterSpacing: letterSpacing,
231231
shadows: textShadow,
232232
wordSpacing: wordSpacing,
233-
height: lineHeight,
233+
height: lineHeight?.size ?? 1.0,
234234
//TODO background
235235
//TODO textBaseline
236236
);
@@ -286,19 +286,25 @@ class Style {
286286
Style copyOnlyInherited(Style child) {
287287
if (child == null) return this;
288288

289+
FontSize finalFontSize = child.fontSize != null ?
290+
fontSize != null && child.fontSize?.units == "em" ?
291+
FontSize(child.fontSize.size * fontSize.size, "") : child.fontSize
292+
: fontSize != null && fontSize.size < 0 ?
293+
FontSize.percent(100) : fontSize;
294+
LineHeight finalLineHeight = child.lineHeight != null ?
295+
child.lineHeight?.units == "length" ?
296+
LineHeight(child.lineHeight.size / (finalFontSize == null ? 14 : finalFontSize.size), "") : child.lineHeight
297+
: lineHeight;
289298
return child.copyWith(
290299
color: child.color ?? color,
291300
direction: child.direction ?? direction,
292301
display: display == Display.NONE ? display : child.display,
293302
fontFamily: child.fontFamily ?? fontFamily,
294303
fontFeatureSettings: child.fontFeatureSettings ?? fontFeatureSettings,
295-
fontSize: child.fontSize != null ?
296-
fontSize != null && child.fontSize?.units == "em" ?
297-
FontSize(child.fontSize.size * fontSize.size, "") : child.fontSize
298-
: fontSize != null && fontSize.size < 0 ?
299-
FontSize.percent(100) : fontSize,
304+
fontSize: finalFontSize,
300305
fontStyle: child.fontStyle ?? fontStyle,
301306
fontWeight: child.fontWeight ?? fontWeight,
307+
lineHeight: finalLineHeight,
302308
letterSpacing: child.letterSpacing ?? letterSpacing,
303309
listStyleType: child.listStyleType ?? listStyleType,
304310
listStylePosition: child.listStylePosition ?? listStylePosition,
@@ -320,7 +326,7 @@ class Style {
320326
FontStyle fontStyle,
321327
FontWeight fontWeight,
322328
double height,
323-
double lineHeight,
329+
LineHeight lineHeight,
324330
double letterSpacing,
325331
ListStyleType listStyleType,
326332
ListStylePosition listStylePosition,
@@ -393,7 +399,7 @@ class Style {
393399
this.letterSpacing = textStyle.letterSpacing;
394400
this.textShadow = textStyle.shadows;
395401
this.wordSpacing = textStyle.wordSpacing;
396-
this.lineHeight = textStyle.height;
402+
this.lineHeight = LineHeight(textStyle.height ?? 1.0, "");
397403
}
398404
}
399405

@@ -421,7 +427,6 @@ class FontSize {
421427
}
422428

423429
factory FontSize.rem(double rem) {
424-
print(rem * 16 - 2);
425430
return FontSize(rem * 16 - 2, "rem");
426431
}
427432
// These values are calculated based off of the default (`medium`)
@@ -442,6 +447,31 @@ class FontSize {
442447
static const larger = FontSize(-1.2, "");
443448
}
444449

450+
class LineHeight {
451+
final double size;
452+
final String units;
453+
454+
const LineHeight(this.size, this.units);
455+
456+
factory LineHeight.percent(double percent) {
457+
return LineHeight(percent / 100.0, "%");
458+
}
459+
460+
factory LineHeight.em(double em) {
461+
return LineHeight(em, "em");
462+
}
463+
464+
factory LineHeight.rem(double rem) {
465+
return LineHeight(rem, "rem");
466+
}
467+
468+
factory LineHeight.number(double num) {
469+
return LineHeight(num, "number");
470+
}
471+
472+
static const normal = LineHeight(1.0, "");
473+
}
474+
445475
enum ListStyleType {
446476
DISC,
447477
DECIMAL,

0 commit comments

Comments
 (0)