Skip to content

Commit 75387db

Browse files
authored
TextStyle.height property as a multiple of font size instead of multiple of ascent+descent+leading. (flutter#9041)
1 parent eb89d9d commit 75387db

File tree

9 files changed

+305
-123
lines changed

9 files changed

+305
-123
lines changed

lib/stub_ui/lib/src/ui/text.dart

Lines changed: 21 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -298,7 +298,8 @@ class TextStyle {
298298
/// * `letterSpacing`: The amount of space (in logical pixels) to add between each letter.
299299
/// * `wordSpacing`: The amount of space (in logical pixels) to add at each sequence of white-space (i.e. between each word).
300300
/// * `textBaseline`: The common baseline that should be aligned between this text span and its parent text span, or, for the root text spans, with the line box.
301-
/// * `height`: The height of this text span, as a multiple of the font size.
301+
/// * `height`: The height of this text span, as a multiplier of the font size. Omitting `height` will allow the line height
302+
/// to take the height as defined by the font, which may not be exactly the height of the fontSize.
302303
/// * `locale`: The locale used to select region-specific glyphs.
303304
/// * `background`: The paint drawn as a background for the text.
304305
/// * `foreground`: The paint used to draw the text. If this is specified, `color` must be null.
@@ -623,13 +624,11 @@ class ParagraphStyle {
623624
/// * `fontSize`: The size of glyphs (in logical pixels) to use when painting
624625
/// the text.
625626
///
626-
/// * `height`: The minimum height of the line boxes, as a multiple of the
627-
/// font size. The lines of the paragraph will be at least
628-
/// `(height + leading) * fontSize` tall when fontSize
629-
/// is not null. When fontSize is null, there is no minimum line height. Tall
630-
/// glyphs due to baseline alignment or large [TextStyle.fontSize] may cause
631-
/// the actual line height after layout to be taller than specified here.
632-
/// [fontSize] must be provided for this property to take effect.
627+
/// * `height`: The fallback height of the spans as a multiplier of the font
628+
/// size. The fallback height is used when no height is provided through
629+
/// [TextStyle.height]. Omitting `height` here and in [TextStyle] will allow
630+
/// the line height to take the height as defined by the font, which may not
631+
/// be exactly the height of the `fontSize`.
633632
///
634633
/// * `fontWeight`: The typeface thickness to use when painting the text
635634
/// (e.g., bold).
@@ -764,22 +763,24 @@ class StrutStyle {
764763
/// * `fontFamily`: The name of the font to use when painting the text (e.g.,
765764
/// Roboto).
766765
///
767-
/// * `fontFamilyFallback`: An ordered list of font family names that will be searched for when
768-
/// the font in `fontFamily` cannot be found.
766+
/// * `fontFamilyFallback`: An ordered list of font family names that will be
767+
/// searched for when the font in `fontFamily` cannot be found.
769768
///
770769
/// * `fontSize`: The size of glyphs (in logical pixels) to use when painting
771770
/// the text.
772771
///
773-
/// * `lineHeight`: The minimum height of the line boxes, as a multiple of the
772+
/// * `height`: The minimum height of the line boxes, as a multiplier of the
774773
/// font size. The lines of the paragraph will be at least
775-
/// `(lineHeight + leading) * fontSize` tall when fontSize
776-
/// is not null. When fontSize is null, there is no minimum line height. Tall
777-
/// glyphs due to baseline alignment or large [TextStyle.fontSize] may cause
778-
/// the actual line height after layout to be taller than specified here.
779-
/// [fontSize] must be provided for this property to take effect.
774+
/// `(height + leading) * fontSize` tall when `fontSize` is not null. Omitting
775+
/// `height` will allow the minimum line height to take the height as defined
776+
/// by the font, which may not be exactly the height of the `fontSize`. When
777+
/// `fontSize` is null, there is no minimum line height. Tall glyphs due to
778+
/// baseline alignment or large [TextStyle.fontSize] may cause the actual line
779+
/// height after layout to be taller than specified here. The `fontSize` must
780+
/// be provided for this property to take effect.
780781
///
781782
/// * `leading`: The minimum amount of leading between lines as a multiple of
782-
/// the font size. [fontSize] must be provided for this property to take effect.
783+
/// the font size. `fontSize` must be provided for this property to take effect.
783784
///
784785
/// * `fontWeight`: The typeface thickness to use when painting the text
785786
/// (e.g., bold).
@@ -788,11 +789,11 @@ class StrutStyle {
788789
/// italics).
789790
///
790791
/// * `forceStrutHeight`: When true, the paragraph will force all lines to be exactly
791-
/// `(lineHeight + leading) * fontSize` tall from baseline to baseline.
792+
/// `(height + leading) * fontSize` tall from baseline to baseline.
792793
/// [TextStyle] is no longer able to influence the line height, and any tall
793-
/// glyphs may overlap with lines above. If a [fontFamily] is specified, the
794+
/// glyphs may overlap with lines above. If a `fontFamily` is specified, the
794795
/// total ascent of the first line will be the min of the `Ascent + half-leading`
795-
/// of the [fontFamily] and `(lineHeight + leading) * fontSize`. Otherwise, it
796+
/// of the `fontFamily` and `(height + leading) * fontSize`. Otherwise, it
796797
/// will be determined by the Ascent + half-leading of the first text.
797798
StrutStyle({
798799
String fontFamily,

lib/ui/text.dart

Lines changed: 20 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -527,7 +527,8 @@ class TextStyle {
527527
/// * `letterSpacing`: The amount of space (in logical pixels) to add between each letter.
528528
/// * `wordSpacing`: The amount of space (in logical pixels) to add at each sequence of white-space (i.e. between each word).
529529
/// * `textBaseline`: The common baseline that should be aligned between this text span and its parent text span, or, for the root text spans, with the line box.
530-
/// * `height`: The height of this text span, as a multiplier of the font size.
530+
/// * `height`: The height of this text span, as a multiplier of the font size. Omitting `height` will allow the line height
531+
/// to take the height as defined by the font, which may not be exactly the height of the fontSize.
531532
/// * `locale`: The locale used to select region-specific glyphs.
532533
/// * `background`: The paint drawn as a background for the text.
533534
/// * `foreground`: The paint used to draw the text. If this is specified, `color` must be null.
@@ -776,9 +777,11 @@ class ParagraphStyle {
776777
/// * `fontSize`: The fallback size of glyphs (in logical pixels) to
777778
/// use when painting the text. This is used when there is no [TextStyle].
778779
///
779-
/// * `height`: The height of the spans as a multiplier of the font size. The
780-
/// fallback height to use when no height is provided in through
781-
/// [TextStyle.height].
780+
/// * `height`: The fallback height of the spans as a multiplier of the font
781+
/// size. The fallback height is used when no height is provided through
782+
/// [TextStyle.height]. Omitting `height` here and in [TextStyle] will allow
783+
/// the line height to take the height as defined by the font, which may not
784+
/// be exactly the height of the `fontSize`.
782785
///
783786
/// * `fontWeight`: The typeface thickness to use when painting the text
784787
/// (e.g., bold).
@@ -962,22 +965,24 @@ class StrutStyle {
962965
/// * `fontFamily`: The name of the font to use when painting the text (e.g.,
963966
/// Roboto).
964967
///
965-
/// * `fontFamilyFallback`: An ordered list of font family names that will be searched for when
966-
/// the font in `fontFamily` cannot be found.
968+
/// * `fontFamilyFallback`: An ordered list of font family names that will be
969+
/// searched for when the font in `fontFamily` cannot be found.
967970
///
968971
/// * `fontSize`: The size of glyphs (in logical pixels) to use when painting
969972
/// the text.
970973
///
971974
/// * `height`: The minimum height of the line boxes, as a multiplier of the
972-
/// font size. The lines of the paragraph will be at least `(height + leading)
973-
/// * fontSize` tall when fontSize is not null. When fontSize is null, there
974-
/// is no minimum line height. Tall glyphs due to baseline alignment or large
975-
/// [TextStyle.fontSize] may cause the actual line height after layout to be
976-
/// taller than specified here. [fontSize] must be provided for this property
977-
/// to take effect.
975+
/// font size. The lines of the paragraph will be at least
976+
/// `(height + leading) * fontSize` tall when `fontSize` is not null. Omitting
977+
/// `height` will allow the minimum line height to take the height as defined
978+
/// by the font, which may not be exactly the height of the `fontSize`. When
979+
/// `fontSize` is null, there is no minimum line height. Tall glyphs due to
980+
/// baseline alignment or large [TextStyle.fontSize] may cause the actual line
981+
/// height after layout to be taller than specified here. The `fontSize` must
982+
/// be provided for this property to take effect.
978983
///
979984
/// * `leading`: The minimum amount of leading between lines as a multiple of
980-
/// the font size. [fontSize] must be provided for this property to take effect.
985+
/// the font size. `fontSize` must be provided for this property to take effect.
981986
///
982987
/// * `fontWeight`: The typeface thickness to use when painting the text
983988
/// (e.g., bold).
@@ -988,9 +993,9 @@ class StrutStyle {
988993
/// * `forceStrutHeight`: When true, the paragraph will force all lines to be exactly
989994
/// `(height + leading) * fontSize` tall from baseline to baseline.
990995
/// [TextStyle] is no longer able to influence the line height, and any tall
991-
/// glyphs may overlap with lines above. If a [fontFamily] is specified, the
996+
/// glyphs may overlap with lines above. If a `fontFamily` is specified, the
992997
/// total ascent of the first line will be the min of the `Ascent + half-leading`
993-
/// of the [fontFamily] and `(height + leading) * fontSize`. Otherwise, it
998+
/// of the `fontFamily` and `(height + leading) * fontSize`. Otherwise, it
994999
/// will be determined by the Ascent + half-leading of the first text.
9951000
StrutStyle({
9961001
String fontFamily,

lib/ui/text/paragraph_builder.cc

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,7 @@ void decodeStrut(Dart_Handle strut_data,
204204
}
205205
if (mask & sHeightMask) {
206206
paragraph_style.strut_height = float_data[float_count++];
207+
paragraph_style.strut_has_height_override = true;
207208
}
208209
if (mask & sLeadingMask) {
209210
paragraph_style.strut_leading = float_data[float_count++];
@@ -261,6 +262,7 @@ ParagraphBuilder::ParagraphBuilder(
261262

262263
if (mask & psHeightMask) {
263264
style.height = height;
265+
style.has_height_override = true;
264266
}
265267

266268
if (mask & psStrutStyleMask) {
@@ -401,6 +403,7 @@ void ParagraphBuilder::pushStyle(tonic::Int32List& encoded,
401403

402404
if (mask & tsHeightMask) {
403405
style.height = height;
406+
style.has_height_override = true;
404407
}
405408

406409
if (mask & tsLocaleMask) {

third_party/txt/src/txt/paragraph.cc

Lines changed: 39 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -538,14 +538,30 @@ void Paragraph::ComputeStrut(StrutMetrics* strut, SkFont& font) {
538538
SkFontMetrics strut_metrics;
539539
font.getMetrics(&strut_metrics);
540540

541-
strut->ascent = paragraph_style_.strut_height * -strut_metrics.fAscent;
542-
strut->descent = paragraph_style_.strut_height * strut_metrics.fDescent;
543-
strut->leading =
544-
// Use font's leading if there is no user specified strut leading.
545-
paragraph_style_.strut_leading < 0
546-
? strut_metrics.fLeading
547-
: (paragraph_style_.strut_leading *
548-
(strut_metrics.fDescent - strut_metrics.fAscent));
541+
if (paragraph_style_.strut_has_height_override) {
542+
double metrics_height = -strut_metrics.fAscent + strut_metrics.fDescent;
543+
strut->ascent = (-strut_metrics.fAscent / metrics_height) *
544+
paragraph_style_.strut_height *
545+
paragraph_style_.strut_font_size;
546+
strut->descent = (strut_metrics.fDescent / metrics_height) *
547+
paragraph_style_.strut_height *
548+
paragraph_style_.strut_font_size;
549+
strut->leading =
550+
// Zero leading if there is no user specified strut leading.
551+
paragraph_style_.strut_leading < 0
552+
? 0
553+
: (paragraph_style_.strut_leading *
554+
paragraph_style_.strut_font_size);
555+
} else {
556+
strut->ascent = -strut_metrics.fAscent;
557+
strut->descent = strut_metrics.fDescent;
558+
strut->leading =
559+
// Use font's leading if there is no user specified strut leading.
560+
paragraph_style_.strut_leading < 0
561+
? strut_metrics.fLeading
562+
: (paragraph_style_.strut_leading *
563+
paragraph_style_.strut_font_size);
564+
}
549565
strut->half_leading = strut->leading / 2;
550566
strut->line_height = strut->ascent + strut->descent + strut->leading;
551567
}
@@ -1073,11 +1089,21 @@ void Paragraph::Layout(double width, bool force) {
10731089
const TextStyle& style,
10741090
PlaceholderRun* placeholder_run) {
10751091
if (!strut_.force_strut) {
1076-
double ascent =
1077-
(-metrics.fAscent + metrics.fLeading / 2) * style.height;
1078-
double descent =
1079-
(metrics.fDescent + metrics.fLeading / 2) * style.height;
1080-
1092+
double ascent;
1093+
double descent;
1094+
if (style.has_height_override) {
1095+
// Scale the ascent and descent such that the sum of ascent and
1096+
// descent is `fontsize * style.height * style.font_size`.
1097+
double metrics_height = -metrics.fAscent + metrics.fDescent;
1098+
ascent = (-metrics.fAscent / metrics_height) * style.height *
1099+
style.font_size;
1100+
descent = (metrics.fDescent / metrics_height) * style.height *
1101+
style.font_size;
1102+
} else {
1103+
// Use the font-provided ascent, descent, and leading directly.
1104+
ascent = (-metrics.fAscent + metrics.fLeading / 2);
1105+
descent = (metrics.fDescent + metrics.fLeading / 2);
1106+
}
10811107
ComputePlaceholder(placeholder_run, ascent, descent);
10821108

10831109
max_ascent = std::max(ascent, max_ascent);

third_party/txt/src/txt/paragraph_style.cc

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,10 @@
1414
* limitations under the License.
1515
*/
1616

17-
#include <vector>
18-
1917
#include "paragraph_style.h"
2018

19+
#include <vector>
20+
2121
namespace txt {
2222

2323
TextStyle ParagraphStyle::GetTextStyle() const {
@@ -30,6 +30,7 @@ TextStyle ParagraphStyle::GetTextStyle() const {
3030
}
3131
result.locale = locale;
3232
result.height = height;
33+
result.has_height_override = has_height_override;
3334
return result;
3435
}
3536

third_party/txt/src/txt/paragraph_style.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ class ParagraphStyle {
5050
std::string font_family = "";
5151
double font_size = 14;
5252
double height = 1;
53+
bool has_height_override = false;
5354

5455
// Strut properties. strut_enabled must be set to true for the rest of the
5556
// properties to take effect.
@@ -60,6 +61,7 @@ class ParagraphStyle {
6061
std::vector<std::string> strut_font_families;
6162
double strut_font_size = 14;
6263
double strut_height = 1;
64+
bool strut_has_height_override = false;
6365
double strut_leading = -1; // Negative to use font's default leading. [0,inf)
6466
// to use custom leading as a ratio of font size.
6567
bool force_strut_height = false;

third_party/txt/src/txt/text_style.cc

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
*/
1616

1717
#include "text_style.h"
18+
1819
#include "font_style.h"
1920
#include "font_weight.h"
2021
#include "third_party/skia/include/core/SkColor.h"
@@ -46,6 +47,8 @@ bool TextStyle::equals(const TextStyle& other) const {
4647
return false;
4748
if (height != other.height)
4849
return false;
50+
if (has_height_override != other.has_height_override)
51+
return false;
4952
if (locale != other.locale)
5053
return false;
5154
if (foreground != other.foreground)

third_party/txt/src/txt/text_style.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ class TextStyle {
5151
double letter_spacing = 0.0;
5252
double word_spacing = 0.0;
5353
double height = 1.0;
54+
bool has_height_override = false;
5455
std::string locale;
5556
bool has_background = false;
5657
SkPaint background;

0 commit comments

Comments
 (0)