mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
[web] Put the paragraph painting logic in the Paragraph class (flutter/engine#22239)
This commit is contained in:
parent
fc87f2df63
commit
d4e264f851
@ -777,70 +777,37 @@ class BitmapCanvas extends EngineCanvas {
|
||||
_childOverdraw = true;
|
||||
}
|
||||
|
||||
void _drawTextLine(
|
||||
ParagraphGeometricStyle style,
|
||||
EngineLineMetrics line,
|
||||
double x,
|
||||
double y,
|
||||
) {
|
||||
html.CanvasRenderingContext2D ctx = _canvasPool.context;
|
||||
x += line.left;
|
||||
final double? letterSpacing = style.letterSpacing;
|
||||
if (letterSpacing == null || letterSpacing == 0.0) {
|
||||
ctx.fillText(line.displayText!, x, y);
|
||||
} else {
|
||||
// When letter-spacing is set, we go through a more expensive code path
|
||||
// that renders each character separately with the correct spacing
|
||||
// between them.
|
||||
//
|
||||
// We are drawing letter spacing like the web does it, by adding the
|
||||
// spacing after each letter. This is different from Flutter which puts
|
||||
// the spacing around each letter i.e. for a 10px letter spacing, Flutter
|
||||
// would put 5px before each letter and 5px after it, but on the web, we
|
||||
// put no spacing before the letter and 10px after it. This is how the DOM
|
||||
// does it.
|
||||
final int len = line.displayText!.length;
|
||||
for (int i = 0; i < len; i++) {
|
||||
final String char = line.displayText![i];
|
||||
ctx.fillText(char, x, y);
|
||||
x += letterSpacing + ctx.measureText(char).width!;
|
||||
}
|
||||
void setFontFromParagraphStyle(ParagraphGeometricStyle style) {
|
||||
if (style != _cachedLastStyle) {
|
||||
html.CanvasRenderingContext2D ctx = _canvasPool.context;
|
||||
ctx.font = style.cssFontString;
|
||||
_cachedLastStyle = style;
|
||||
}
|
||||
}
|
||||
|
||||
/// Measures the given [text] and returns a [html.TextMetrics] object that
|
||||
/// contains information about the measurement.
|
||||
///
|
||||
/// The text is measured using the font set by the most recent call to
|
||||
/// [setFontFromParagraphStyle].
|
||||
html.TextMetrics measureText(String text) {
|
||||
return _canvasPool.context.measureText(text);
|
||||
}
|
||||
|
||||
/// Draws text to the canvas starting at coordinate ([x], [y]).
|
||||
///
|
||||
/// The text is drawn starting at coordinates ([x], [y]). It uses the current
|
||||
/// font set by the most recent call to [setFontFromParagraphStyle].
|
||||
void fillText(String text, double x, double y) {
|
||||
_canvasPool.context.fillText(text, x, y);
|
||||
}
|
||||
|
||||
@override
|
||||
void drawParagraph(EngineParagraph paragraph, ui.Offset offset) {
|
||||
assert(paragraph._isLaidOut);
|
||||
final ParagraphGeometricStyle style = paragraph._geometricStyle;
|
||||
|
||||
if (paragraph._drawOnCanvas && _childOverdraw == false) {
|
||||
// !Do not move this assignment above this if clause since, accessing
|
||||
// context will generate extra <canvas> tags.
|
||||
final List<EngineLineMetrics> lines =
|
||||
paragraph._measurementResult!.lines!;
|
||||
|
||||
final SurfacePaintData? backgroundPaint =
|
||||
paragraph._background?.paintData;
|
||||
if (backgroundPaint != null) {
|
||||
final ui.Rect rect = ui.Rect.fromLTWH(
|
||||
offset.dx, offset.dy, paragraph.width, paragraph.height);
|
||||
drawRect(rect, backgroundPaint);
|
||||
}
|
||||
|
||||
if (style != _cachedLastStyle) {
|
||||
html.CanvasRenderingContext2D ctx = _canvasPool.context;
|
||||
ctx.font = style.cssFontString;
|
||||
_cachedLastStyle = style;
|
||||
}
|
||||
_setUpPaint(paragraph._paint!.paintData, null);
|
||||
double y = offset.dy + paragraph.alphabeticBaseline;
|
||||
final int len = lines.length;
|
||||
for (int i = 0; i < len; i++) {
|
||||
_drawTextLine(style, lines[i], offset.dx, y);
|
||||
y += paragraph._lineHeight;
|
||||
}
|
||||
_tearDownPaint();
|
||||
assert(paragraph.isLaidOut);
|
||||
|
||||
if (paragraph.drawOnCanvas && _childOverdraw == false) {
|
||||
paragraph.paint(this, offset);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@ -251,18 +251,12 @@ html.Element _drawParagraphElement(
|
||||
ui.Offset offset, {
|
||||
Matrix4? transform,
|
||||
}) {
|
||||
assert(paragraph._isLaidOut);
|
||||
assert(paragraph.isLaidOut);
|
||||
|
||||
final html.Element paragraphElement = paragraph._paragraphElement.clone(true) as html.Element;
|
||||
|
||||
final html.CssStyleDeclaration paragraphStyle = paragraphElement.style;
|
||||
paragraphStyle
|
||||
..position = 'absolute'
|
||||
..whiteSpace = 'pre-wrap'
|
||||
..overflowWrap = 'break-word'
|
||||
..overflow = 'hidden'
|
||||
..height = '${paragraph.height}px'
|
||||
..width = '${paragraph.width}px';
|
||||
final html.HtmlElement paragraphElement = paragraph.toDomElement();
|
||||
paragraphElement.style
|
||||
..height = '${paragraph.height}px'
|
||||
..width = '${paragraph.width}px';
|
||||
|
||||
if (transform != null) {
|
||||
setElementTransform(
|
||||
@ -270,16 +264,6 @@ html.Element _drawParagraphElement(
|
||||
transformWithOffset(transform, offset).storage,
|
||||
);
|
||||
}
|
||||
|
||||
final ParagraphGeometricStyle style = paragraph._geometricStyle;
|
||||
|
||||
// TODO(flutter_web): https://github.com/flutter/flutter/issues/33223
|
||||
if (style.ellipsis != null &&
|
||||
(style.maxLines == null || style.maxLines == 1)) {
|
||||
paragraphStyle
|
||||
..whiteSpace = 'pre'
|
||||
..textOverflow = 'ellipsis';
|
||||
}
|
||||
return paragraphElement;
|
||||
}
|
||||
|
||||
|
||||
@ -522,13 +522,13 @@ class RecordingCanvas {
|
||||
void drawParagraph(ui.Paragraph paragraph, ui.Offset offset) {
|
||||
assert(!_recordingEnded);
|
||||
final EngineParagraph engineParagraph = paragraph as EngineParagraph;
|
||||
if (!engineParagraph._isLaidOut) {
|
||||
if (!engineParagraph.isLaidOut) {
|
||||
// Ignore non-laid out paragraphs. This matches Flutter's behavior.
|
||||
return;
|
||||
}
|
||||
|
||||
_didDraw = true;
|
||||
if (engineParagraph._geometricStyle.ellipsis != null) {
|
||||
if (engineParagraph.hasArbitraryPaint) {
|
||||
_hasArbitraryPaint = true;
|
||||
}
|
||||
final double left = offset.dx;
|
||||
|
||||
@ -335,9 +335,94 @@ class EngineParagraph implements ui.Paragraph {
|
||||
}
|
||||
}
|
||||
|
||||
bool get hasArbitraryPaint => _geometricStyle.ellipsis != null;
|
||||
|
||||
void paint(BitmapCanvas canvas, ui.Offset offset) {
|
||||
assert(drawOnCanvas);
|
||||
assert(isLaidOut);
|
||||
|
||||
// Paint the background first.
|
||||
final SurfacePaint? background = _background;
|
||||
if (background != null) {
|
||||
final ui.Rect rect = ui.Rect.fromLTWH(offset.dx, offset.dy, width, height);
|
||||
canvas.drawRect(rect, background.paintData);
|
||||
}
|
||||
|
||||
final List<EngineLineMetrics> lines = _measurementResult!.lines!;
|
||||
canvas.setFontFromParagraphStyle(_geometricStyle);
|
||||
|
||||
// Then paint the text.
|
||||
canvas._setUpPaint(_paint!.paintData, null);
|
||||
double y = offset.dy + alphabeticBaseline;
|
||||
final int len = lines.length;
|
||||
for (int i = 0; i < len; i++) {
|
||||
_paintLine(canvas, lines[i], offset.dx, y);
|
||||
y += _lineHeight;
|
||||
}
|
||||
canvas._tearDownPaint();
|
||||
}
|
||||
|
||||
void _paintLine(
|
||||
BitmapCanvas canvas,
|
||||
EngineLineMetrics line,
|
||||
double x,
|
||||
double y,
|
||||
) {
|
||||
x += line.left;
|
||||
final double? letterSpacing = _geometricStyle.letterSpacing;
|
||||
if (letterSpacing == null || letterSpacing == 0.0) {
|
||||
canvas.fillText(line.displayText!, x, y);
|
||||
} else {
|
||||
// When letter-spacing is set, we go through a more expensive code path
|
||||
// that renders each character separately with the correct spacing
|
||||
// between them.
|
||||
//
|
||||
// We are drawing letter spacing like the web does it, by adding the
|
||||
// spacing after each letter. This is different from Flutter which puts
|
||||
// the spacing around each letter i.e. for a 10px letter spacing, Flutter
|
||||
// would put 5px before each letter and 5px after it, but on the web, we
|
||||
// put no spacing before the letter and 10px after it. This is how the DOM
|
||||
// does it.
|
||||
//
|
||||
// TODO(mdebbar): Implement letter-spacing on canvas more efficiently:
|
||||
// https://github.com/flutter/flutter/issues/51234
|
||||
final int len = line.displayText!.length;
|
||||
for (int i = 0; i < len; i++) {
|
||||
final String char = line.displayText![i];
|
||||
canvas.fillText(char, x, y);
|
||||
x += letterSpacing + canvas.measureText(char).width!;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
html.HtmlElement toDomElement() {
|
||||
assert(isLaidOut);
|
||||
|
||||
final html.HtmlElement paragraphElement =
|
||||
_paragraphElement.clone(true) as html.HtmlElement;
|
||||
|
||||
final html.CssStyleDeclaration paragraphStyle = paragraphElement.style;
|
||||
paragraphStyle
|
||||
..position = 'absolute'
|
||||
..whiteSpace = 'pre-wrap'
|
||||
..overflowWrap = 'break-word'
|
||||
..overflow = 'hidden';
|
||||
|
||||
final ParagraphGeometricStyle style = _geometricStyle;
|
||||
|
||||
// TODO(flutter_web): https://github.com/flutter/flutter/issues/33223
|
||||
if (style.ellipsis != null &&
|
||||
(style.maxLines == null || style.maxLines == 1)) {
|
||||
paragraphStyle
|
||||
..whiteSpace = 'pre'
|
||||
..textOverflow = 'ellipsis';
|
||||
}
|
||||
return paragraphElement;
|
||||
}
|
||||
|
||||
@override
|
||||
List<ui.TextBox> getBoxesForPlaceholders() {
|
||||
assert(_isLaidOut);
|
||||
assert(isLaidOut);
|
||||
return _measurementResult!.placeholderBoxes;
|
||||
}
|
||||
|
||||
@ -351,7 +436,7 @@ class EngineParagraph implements ui.Paragraph {
|
||||
/// - Paragraphs that contain decorations.
|
||||
/// - Paragraphs that have a non-null word-spacing.
|
||||
/// - Paragraphs with a background.
|
||||
bool get _drawOnCanvas {
|
||||
bool get drawOnCanvas {
|
||||
if (!_hasLineMetrics) {
|
||||
return false;
|
||||
}
|
||||
@ -370,7 +455,7 @@ class EngineParagraph implements ui.Paragraph {
|
||||
}
|
||||
|
||||
/// Whether this paragraph has been laid out.
|
||||
bool get _isLaidOut => _measurementResult != null;
|
||||
bool get isLaidOut => _measurementResult != null;
|
||||
|
||||
/// Asserts that the properties used to measure paragraph layout are the same
|
||||
/// as the properties of this paragraphs root style.
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user