Skip to content

Commit a3e883b

Browse files
authored
[web] Fixes for Firefox & Safari double underline decoration bugs. (flutter#16994)
* Work around line measurement rounding bug in Firefox. Add -webkit prefix for Safari text decoration * Add check for measurement tests for firefox
1 parent a18066b commit a3e883b

File tree

2 files changed

+54
-25
lines changed

2 files changed

+54
-25
lines changed

lib/web_ui/lib/src/engine/text/paragraph.dart

Lines changed: 29 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -396,11 +396,13 @@ class EngineParagraph implements ui.Paragraph {
396396

397397
ui.TextBox _getBoxForLine(EngineLineMetrics line, int start, int end) {
398398
final double widthBeforeBox = start <= line.startIndex
399-
? 0.0
400-
: _measurementService.measureSubstringWidth(this, line.startIndex, start);
399+
? 0.0
400+
: _measurementService.measureSubstringWidth(
401+
this, line.startIndex, start);
401402
final double widthAfterBox = end >= line.endIndexWithoutNewlines
402-
? 0.0
403-
: _measurementService.measureSubstringWidth(this, end, line.endIndexWithoutNewlines);
403+
? 0.0
404+
: _measurementService.measureSubstringWidth(
405+
this, end, line.endIndexWithoutNewlines);
404406

405407
final double top = line.lineNumber * _lineHeight;
406408

@@ -488,7 +490,8 @@ class EngineParagraph implements ui.Paragraph {
488490
int high = lineMetrics.endIndexWithoutNewlines;
489491
do {
490492
final int current = (low + high) ~/ 2;
491-
final double width = instance.measureSubstringWidth(this, lineMetrics.startIndex, current);
493+
final double width =
494+
instance.measureSubstringWidth(this, lineMetrics.startIndex, current);
492495
if (width < dx) {
493496
low = current;
494497
} else if (width > dx) {
@@ -503,8 +506,10 @@ class EngineParagraph implements ui.Paragraph {
503506
return ui.TextPosition(offset: high, affinity: ui.TextAffinity.upstream);
504507
}
505508

506-
final double lowWidth = instance.measureSubstringWidth(this, lineMetrics.startIndex, low);
507-
final double highWidth = instance.measureSubstringWidth(this, lineMetrics.startIndex, high);
509+
final double lowWidth =
510+
instance.measureSubstringWidth(this, lineMetrics.startIndex, low);
511+
final double highWidth =
512+
instance.measureSubstringWidth(this, lineMetrics.startIndex, high);
508513

509514
if (dx - lowWidth < highWidth - dx) {
510515
// The offset is closer to the low index.
@@ -666,18 +671,17 @@ class EngineParagraphStyle implements ui.ParagraphStyle {
666671
@override
667672
int get hashCode {
668673
return ui.hashValues(
669-
_textAlign,
670-
_textDirection,
671-
_fontWeight,
672-
_fontStyle,
673-
_maxLines,
674-
_fontFamily,
675-
_fontSize,
676-
_height,
677-
_textHeightBehavior,
678-
_ellipsis,
679-
_locale
680-
);
674+
_textAlign,
675+
_textDirection,
676+
_fontWeight,
677+
_fontStyle,
678+
_maxLines,
679+
_fontFamily,
680+
_fontSize,
681+
_height,
682+
_textHeightBehavior,
683+
_ellipsis,
684+
_locale);
681685
}
682686

683687
@override
@@ -1500,7 +1504,12 @@ void _applyTextStyleToElement({
15001504
final String textDecoration =
15011505
_textDecorationToCssString(style._decoration, style._decorationStyle);
15021506
if (textDecoration != null) {
1503-
cssStyle.textDecoration = textDecoration;
1507+
if (browserEngine == BrowserEngine.webkit) {
1508+
domRenderer.setElementStyle(
1509+
element, '-webkit-text-decoration', textDecoration);
1510+
} else {
1511+
cssStyle.textDecoration = textDecoration;
1512+
}
15041513
final ui.Color decorationColor = style._decorationColor;
15051514
if (decorationColor != null) {
15061515
cssStyle.textDecorationColor = colorToCssString(decorationColor);

lib/web_ui/lib/src/engine/text/ruler.dart

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -244,7 +244,8 @@ class TextDimensions {
244244

245245
/// Applies geometric style properties to the [element].
246246
void applyStyle(ParagraphGeometricStyle style) {
247-
_element.style
247+
final html.CssStyleDeclaration elementStyle = _element.style;
248+
elementStyle
248249
..fontSize = style.fontSize != null ? '${style.fontSize.floor()}px' : null
249250
..fontFamily = canonicalizeFontFamily(style.effectiveFontFamily)
250251
..fontWeight =
@@ -255,10 +256,16 @@ class TextDimensions {
255256
..letterSpacing =
256257
style.letterSpacing != null ? '${style.letterSpacing}px' : null
257258
..wordSpacing =
258-
style.wordSpacing != null ? '${style.wordSpacing}px' : null
259-
..textDecoration = style.decoration;
259+
style.wordSpacing != null ? '${style.wordSpacing}px' : null;
260+
final String decoration = style.decoration;
261+
if (browserEngine == BrowserEngine.webkit) {
262+
domRenderer.setElementStyle(
263+
_element, '-webkit-text-decoration', decoration);
264+
} else {
265+
elementStyle.textDecoration = decoration;
266+
}
260267
if (style.lineHeight != null) {
261-
_element.style.lineHeight = style.lineHeight.toString();
268+
elementStyle.lineHeight = style.lineHeight.toString();
262269
}
263270
_invalidateBoundsCache();
264271
}
@@ -277,7 +284,20 @@ class TextDimensions {
277284
double get width => _readAndCacheMetrics().width;
278285

279286
/// The height of the paragraph being measured.
280-
double get height => _readAndCacheMetrics().height;
287+
double get height {
288+
double cachedHeight = _readAndCacheMetrics().height;
289+
if (browserEngine == BrowserEngine.firefox &&
290+
// In the flutter tester environment, we use a predictable-size for font
291+
// measurement tests.
292+
!ui.debugEmulateFlutterTesterEnvironment) {
293+
// See subpixel rounding bug :
294+
// https://bugzilla.mozilla.org/show_bug.cgi?id=442139
295+
// This causes bottom of letters such as 'y' to be cutoff and
296+
// incorrect rendering of double underlines.
297+
cachedHeight += 1.0;
298+
}
299+
return cachedHeight;
300+
}
281301
}
282302

283303
/// Performs 4 types of measurements:

0 commit comments

Comments
 (0)