[web] Some cleanup for text tests (flutter/engine#36425)
This commit is contained in:
@@ -264,7 +264,7 @@ DomElement drawParagraphElement(
|
||||
}) {
|
||||
assert(paragraph.isLaidOut);
|
||||
|
||||
final DomHTMLElement paragraphElement = paragraph.toDomElement();
|
||||
final DomElement paragraphElement = paragraph.toDomElement();
|
||||
|
||||
if (transform != null) {
|
||||
setElementTransform(
|
||||
|
||||
@@ -1246,7 +1246,7 @@ class PaintDrawParagraph extends DrawCommand {
|
||||
@override
|
||||
String toString() {
|
||||
if (assertionsEnabled) {
|
||||
return 'DrawParagraph(${paragraph.toPlainText()}, $offset)';
|
||||
return 'DrawParagraph(${paragraph.plainText}, $offset)';
|
||||
} else {
|
||||
return super.toString();
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@ import 'word_breaker.dart';
|
||||
|
||||
const ui.Color _defaultTextColor = ui.Color(0xFFFF0000);
|
||||
|
||||
final String _placeholderChar = String.fromCharCode(0xFFFC);
|
||||
final String placeholderChar = String.fromCharCode(0xFFFC);
|
||||
|
||||
/// A paragraph made up of a flat list of text spans and placeholders.
|
||||
///
|
||||
@@ -33,7 +33,6 @@ class CanvasParagraph implements ui.Paragraph {
|
||||
this.spans, {
|
||||
required this.paragraphStyle,
|
||||
required this.plainText,
|
||||
required this.placeholderCount,
|
||||
required this.canDrawOnCanvas,
|
||||
}) : assert(spans.isNotEmpty);
|
||||
|
||||
@@ -46,9 +45,6 @@ class CanvasParagraph implements ui.Paragraph {
|
||||
/// The full textual content of the paragraph.
|
||||
late String plainText;
|
||||
|
||||
/// The number of placeholders in this paragraph.
|
||||
final int placeholderCount;
|
||||
|
||||
/// Whether this paragraph can be drawn on a bitmap canvas.
|
||||
///
|
||||
/// Some text features cannot be rendered into a 2D canvas and must use HTML,
|
||||
@@ -87,8 +83,6 @@ class CanvasParagraph implements ui.Paragraph {
|
||||
/// Whether this paragraph has been laid out or not.
|
||||
bool isLaidOut = false;
|
||||
|
||||
bool get isRtl => paragraphStyle.effectiveTextDirection == ui.TextDirection.rtl;
|
||||
|
||||
ui.ParagraphConstraints? _lastUsedConstraints;
|
||||
|
||||
late final TextLayoutService _layoutService = TextLayoutService(this);
|
||||
@@ -138,27 +132,23 @@ class CanvasParagraph implements ui.Paragraph {
|
||||
_paintService.paint(canvas, offset);
|
||||
}
|
||||
|
||||
/// Generates a flat string computed from all the spans of the paragraph.
|
||||
String toPlainText() => plainText;
|
||||
|
||||
DomHTMLElement? _cachedDomElement;
|
||||
DomElement? _cachedDomElement;
|
||||
|
||||
/// Returns a DOM element that represents the entire paragraph and its
|
||||
/// children.
|
||||
///
|
||||
/// Generates a new DOM element on every invocation.
|
||||
DomHTMLElement toDomElement() {
|
||||
DomElement toDomElement() {
|
||||
assert(isLaidOut);
|
||||
final DomHTMLElement? domElement = _cachedDomElement;
|
||||
final DomElement? domElement = _cachedDomElement;
|
||||
if (domElement == null) {
|
||||
return _cachedDomElement ??= _createDomElement();
|
||||
}
|
||||
return domElement.cloneNode(true) as DomHTMLElement;
|
||||
return domElement.cloneNode(true) as DomElement;
|
||||
}
|
||||
|
||||
DomHTMLElement _createDomElement() {
|
||||
final DomHTMLElement rootElement =
|
||||
domDocument.createElement('flt-paragraph') as DomHTMLElement;
|
||||
DomElement _createDomElement() {
|
||||
final DomElement rootElement = domDocument.createElement('flt-paragraph');
|
||||
|
||||
// 1. Set paragraph-level styles.
|
||||
|
||||
@@ -183,12 +173,8 @@ class CanvasParagraph implements ui.Paragraph {
|
||||
continue;
|
||||
}
|
||||
|
||||
final DomHTMLElement spanElement = domDocument.createElement('flt-span') as DomHTMLElement;
|
||||
applyTextStyleToElement(
|
||||
element: spanElement,
|
||||
style: fragment.style,
|
||||
isSpan: true,
|
||||
);
|
||||
final DomElement spanElement = domDocument.createElement('flt-span');
|
||||
applyTextStyleToElement(element: spanElement, style: fragment.style);
|
||||
_positionSpanElement(spanElement, line, fragment);
|
||||
|
||||
spanElement.appendText(text);
|
||||
@@ -221,7 +207,6 @@ class CanvasParagraph implements ui.Paragraph {
|
||||
|
||||
@override
|
||||
ui.TextRange getWordBoundary(ui.TextPosition position) {
|
||||
final String text = toPlainText();
|
||||
final int characterPosition;
|
||||
switch (position.affinity) {
|
||||
case ui.TextAffinity.upstream:
|
||||
@@ -231,8 +216,8 @@ class CanvasParagraph implements ui.Paragraph {
|
||||
characterPosition = position.offset;
|
||||
break;
|
||||
}
|
||||
final int start = WordBreaker.prevBreakIndex(text, characterPosition + 1);
|
||||
final int end = WordBreaker.nextBreakIndex(text, characterPosition);
|
||||
final int start = WordBreaker.prevBreakIndex(plainText, characterPosition + 1);
|
||||
final int end = WordBreaker.nextBreakIndex(plainText, characterPosition);
|
||||
return ui.TextRange(start: start, end: end);
|
||||
}
|
||||
|
||||
@@ -288,51 +273,30 @@ void _positionSpanElement(DomElement element, ParagraphLine line, LayoutFragment
|
||||
..lineHeight = '${boxRect.height}px';
|
||||
}
|
||||
|
||||
/// A common interface for all types of spans that make up a paragraph.
|
||||
///
|
||||
/// These spans are stored as a flat list in the paragraph object.
|
||||
abstract class ParagraphSpan {
|
||||
/// The index of the beginning of the range of text represented by this span.
|
||||
int get start;
|
||||
|
||||
/// The index of the end of the range of text represented by this span.
|
||||
int get end;
|
||||
|
||||
/// The resolved style of the span.
|
||||
EngineTextStyle get style;
|
||||
}
|
||||
|
||||
/// Represent a span of text in the paragraph.
|
||||
///
|
||||
/// It's a "flat" text span as opposed to the framework text spans that are
|
||||
/// hierarchical.
|
||||
/// Represents a span in the paragraph.
|
||||
///
|
||||
/// Instead of keeping spans and styles in a tree hierarchy like the framework
|
||||
/// does, we flatten the structure and resolve/merge all the styles from parent
|
||||
/// nodes.
|
||||
class FlatTextSpan implements ParagraphSpan {
|
||||
/// Creates a [FlatTextSpan] with the given [style], representing the span of
|
||||
///
|
||||
/// These spans are stored as a flat list in the paragraph object.
|
||||
class ParagraphSpan {
|
||||
/// Creates a [ParagraphSpan] with the given [style], representing the span of
|
||||
/// text in the range between [start] and [end].
|
||||
FlatTextSpan({
|
||||
ParagraphSpan({
|
||||
required this.style,
|
||||
required this.start,
|
||||
required this.end,
|
||||
});
|
||||
|
||||
@override
|
||||
/// The resolved style of the span.
|
||||
final EngineTextStyle style;
|
||||
|
||||
@override
|
||||
/// The index of the beginning of the range of text represented by this span.
|
||||
final int start;
|
||||
|
||||
@override
|
||||
/// The index of the end of the range of text represented by this span.
|
||||
final int end;
|
||||
|
||||
String textOf(CanvasParagraph paragraph) {
|
||||
final String text = paragraph.toPlainText();
|
||||
assert(end <= text.length);
|
||||
return text.substring(start, end);
|
||||
}
|
||||
}
|
||||
|
||||
class PlaceholderSpan extends ParagraphPlaceholder implements ParagraphSpan {
|
||||
@@ -622,16 +586,13 @@ class CanvasParagraphBuilder implements ui.ParagraphBuilder {
|
||||
double? baselineOffset,
|
||||
ui.TextBaseline? baseline,
|
||||
}) {
|
||||
// TODO(mdebbar): for measurement of placeholders, look at:
|
||||
// - https://github.com/flutter/engine/blob/c0f7e8acf9318d264ad6a235facd097de597ffcc/third_party/txt/src/txt/paragraph_txt.cc#L325-L350
|
||||
|
||||
// Require a baseline to be specified if using a baseline-based alignment.
|
||||
assert(!(alignment == ui.PlaceholderAlignment.aboveBaseline ||
|
||||
alignment == ui.PlaceholderAlignment.belowBaseline ||
|
||||
alignment == ui.PlaceholderAlignment.baseline) || baseline != null);
|
||||
|
||||
final int start = _plainTextBuffer.length;
|
||||
_plainTextBuffer.write(_placeholderChar);
|
||||
_plainTextBuffer.write(placeholderChar);
|
||||
final int end = _plainTextBuffer.length;
|
||||
|
||||
final EngineTextStyle style = _currentStyleNode.resolveStyle();
|
||||
@@ -674,7 +635,7 @@ class CanvasParagraphBuilder implements ui.ParagraphBuilder {
|
||||
final EngineTextStyle style = _currentStyleNode.resolveStyle();
|
||||
_updateCanDrawOnCanvas(style);
|
||||
|
||||
_spans.add(FlatTextSpan(style: style, start: start, end: end));
|
||||
_spans.add(ParagraphSpan(style: style, start: start, end: end));
|
||||
}
|
||||
|
||||
void _updateCanDrawOnCanvas(EngineTextStyle style) {
|
||||
@@ -708,18 +669,15 @@ class CanvasParagraphBuilder implements ui.ParagraphBuilder {
|
||||
//
|
||||
// We want the paragraph to always have a non-empty list of spans to match
|
||||
// the expectations of the [LayoutFragmenter].
|
||||
_spans.add(FlatTextSpan(
|
||||
style: _rootStyleNode.resolveStyle(),
|
||||
start: 0,
|
||||
end: 0,
|
||||
));
|
||||
_spans.add(
|
||||
ParagraphSpan(style: _rootStyleNode.resolveStyle(), start: 0, end: 0),
|
||||
);
|
||||
}
|
||||
|
||||
return CanvasParagraph(
|
||||
_spans,
|
||||
paragraphStyle: _paragraphStyle,
|
||||
plainText: _plainTextBuffer.toString(),
|
||||
placeholderCount: _placeholderCount,
|
||||
canDrawOnCanvas: _canDrawOnCanvas,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -360,7 +360,7 @@ class TextLayoutService {
|
||||
return <ui.TextBox>[];
|
||||
}
|
||||
|
||||
final int length = paragraph.toPlainText().length;
|
||||
final int length = paragraph.plainText.length;
|
||||
// Ranges that are out of bounds should return an empty list.
|
||||
if (start > length || end > length) {
|
||||
return <ui.TextBox>[];
|
||||
@@ -1046,10 +1046,9 @@ class Spanometer {
|
||||
assert(start >= currentSpan.start && start <= currentSpan.end);
|
||||
assert(end >= currentSpan.start && end <= currentSpan.end);
|
||||
|
||||
final String text = paragraph.toPlainText();
|
||||
return measureSubstring(
|
||||
context,
|
||||
text,
|
||||
paragraph.plainText,
|
||||
start,
|
||||
end,
|
||||
letterSpacing: letterSpacing,
|
||||
|
||||
@@ -36,15 +36,16 @@ class TextPaintService {
|
||||
ui.Offset offset,
|
||||
LayoutFragment fragment,
|
||||
) {
|
||||
final ParagraphSpan span = fragment.span;
|
||||
if (span is FlatTextSpan) {
|
||||
// Paint the background of the box, if the span has a background.
|
||||
final SurfacePaint? background = span.style.background as SurfacePaint?;
|
||||
if (background != null) {
|
||||
final ui.Rect rect = fragment.toPaintingTextBox().toRect();
|
||||
if (!rect.isEmpty) {
|
||||
canvas.drawRect(rect.shift(offset), background.paintData);
|
||||
}
|
||||
if (fragment.isPlaceholder) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Paint the background of the box, if the span has a background.
|
||||
final SurfacePaint? background = fragment.style.background as SurfacePaint?;
|
||||
if (background != null) {
|
||||
final ui.Rect rect = fragment.toPaintingTextBox().toRect();
|
||||
if (!rect.isEmpty) {
|
||||
canvas.drawRect(rect.shift(offset), background.paintData);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -774,13 +774,9 @@ String fontWeightIndexToCss({int fontWeightIndex = 3}) {
|
||||
|
||||
/// Applies a text [style] to an [element], translating the properties to their
|
||||
/// corresponding CSS equivalents.
|
||||
///
|
||||
/// If [isSpan] is true, the text element is a span within richtext and
|
||||
/// should not assign effectiveFontFamily if fontFamily was not specified.
|
||||
void applyTextStyleToElement({
|
||||
required DomHTMLElement element,
|
||||
required DomElement element,
|
||||
required EngineTextStyle style,
|
||||
bool isSpan = false,
|
||||
}) {
|
||||
assert(element != null);
|
||||
assert(style != null);
|
||||
@@ -822,10 +818,10 @@ void applyTextStyleToElement({
|
||||
}
|
||||
// For test environment use effectiveFontFamily since we need to
|
||||
// consistently use Ahem font.
|
||||
if (isSpan && !ui.debugEmulateFlutterTesterEnvironment) {
|
||||
cssStyle.fontFamily = canonicalizeFontFamily(style.fontFamily)!;
|
||||
} else {
|
||||
if (ui.debugEmulateFlutterTesterEnvironment) {
|
||||
cssStyle.fontFamily = canonicalizeFontFamily(style.effectiveFontFamily)!;
|
||||
} else {
|
||||
cssStyle.fontFamily = canonicalizeFontFamily(style.fontFamily)!;
|
||||
}
|
||||
if (style.letterSpacing != null) {
|
||||
cssStyle.letterSpacing = '${style.letterSpacing}px';
|
||||
|
||||
@@ -2,8 +2,6 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:test/bootstrap/browser.dart';
|
||||
import 'package:test/test.dart';
|
||||
import 'package:ui/src/engine.dart';
|
||||
@@ -12,8 +10,6 @@ import 'package:ui/ui.dart' hide window;
|
||||
import '../screenshot.dart';
|
||||
import 'helper.dart';
|
||||
|
||||
typedef CanvasTest = FutureOr<void> Function(EngineCanvas canvas);
|
||||
|
||||
const String _rtlWord1 = 'واحد';
|
||||
const String _rtlWord2 = 'اثنان';
|
||||
|
||||
|
||||
@@ -13,8 +13,6 @@ import 'package:ui/ui.dart' hide window;
|
||||
import '../screenshot.dart';
|
||||
import 'helper.dart';
|
||||
|
||||
typedef CanvasTest = FutureOr<void> Function(EngineCanvas canvas);
|
||||
|
||||
const Rect bounds = Rect.fromLTWH(0, 0, 800, 600);
|
||||
|
||||
void main() {
|
||||
|
||||
@@ -2,10 +2,14 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:ui/src/engine.dart';
|
||||
import 'package:ui/ui.dart';
|
||||
import 'package:web_engine_tester/golden_tester.dart';
|
||||
|
||||
typedef CanvasTest = FutureOr<void> Function(EngineCanvas canvas);
|
||||
|
||||
const LineBreakType prohibited = LineBreakType.prohibited;
|
||||
const LineBreakType opportunity = LineBreakType.opportunity;
|
||||
const LineBreakType mandatory = LineBreakType.mandatory;
|
||||
@@ -32,6 +36,11 @@ const Color blue = Color(0xFF0000FF);
|
||||
const Color yellow = Color(0xFFFFEB3B);
|
||||
const Color lightPurple = Color(0xFFE1BEE7);
|
||||
|
||||
final EngineParagraphStyle ahemStyle = EngineParagraphStyle(
|
||||
fontFamily: 'ahem',
|
||||
fontSize: 10,
|
||||
);
|
||||
|
||||
ParagraphConstraints constrain(double width) {
|
||||
return ParagraphConstraints(width: width);
|
||||
}
|
||||
@@ -73,10 +82,7 @@ Future<void> takeScreenshot(
|
||||
try {
|
||||
sceneElement.append(canvas.rootElement);
|
||||
domDocument.body!.append(sceneElement);
|
||||
await matchGoldenFile(
|
||||
'$fileName.png',
|
||||
region: region,
|
||||
);
|
||||
await matchGoldenFile('$fileName.png', region: region);
|
||||
} finally {
|
||||
// The page is reused across tests, so remove the element after taking the
|
||||
// Scuba screenshot.
|
||||
@@ -109,3 +115,7 @@ void fillBoxes(EngineCanvas canvas, Offset offset, List<TextBox> boxes, Color co
|
||||
canvas.drawRect(rect, SurfacePaintData()..color = color);
|
||||
}
|
||||
}
|
||||
|
||||
String getSpanText(CanvasParagraph paragraph, ParagraphSpan span) {
|
||||
return paragraph.plainText.substring(span.start, span.end);
|
||||
}
|
||||
|
||||
@@ -12,8 +12,6 @@ import 'package:ui/ui.dart' hide window;
|
||||
import '../screenshot.dart';
|
||||
import 'helper.dart';
|
||||
|
||||
typedef CanvasTest = FutureOr<void> Function(EngineCanvas canvas);
|
||||
|
||||
void main() {
|
||||
internalBootstrapBrowserTest(() => testMain);
|
||||
}
|
||||
|
||||
@@ -12,8 +12,6 @@ import 'package:ui/ui.dart' hide window;
|
||||
import '../screenshot.dart';
|
||||
import 'helper.dart';
|
||||
|
||||
typedef CanvasTest = FutureOr<void> Function(EngineCanvas canvas);
|
||||
|
||||
const Rect bounds = Rect.fromLTWH(0, 0, 800, 600);
|
||||
|
||||
void main() {
|
||||
|
||||
@@ -11,8 +11,6 @@ import 'package:ui/ui.dart' hide window;
|
||||
import '../screenshot.dart';
|
||||
import 'text_scuba.dart';
|
||||
|
||||
typedef CanvasTest = FutureOr<void> Function(EngineCanvas canvas);
|
||||
|
||||
const String threeLines = 'First\nSecond\nThird';
|
||||
const String veryLong =
|
||||
'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.';
|
||||
|
||||
@@ -7,19 +7,13 @@ import 'package:ui/src/engine.dart';
|
||||
import 'package:ui/ui.dart';
|
||||
|
||||
import '../screenshot.dart';
|
||||
import 'helper.dart';
|
||||
import 'text_scuba.dart';
|
||||
|
||||
typedef PaintTest = void Function(RecordingCanvas recordingCanvas);
|
||||
|
||||
void main() {
|
||||
internalBootstrapBrowserTest(() => testMain);
|
||||
}
|
||||
|
||||
/// Whether we are running on iOS Safari.
|
||||
// TODO(mdebbar): https://github.com/flutter/flutter/issues/66656
|
||||
bool get isIosSafari => browserEngine == BrowserEngine.webkit &&
|
||||
operatingSystem == OperatingSystem.iOs;
|
||||
|
||||
Future<void> testMain() async {
|
||||
final EngineScubaTester scuba = await EngineScubaTester.initialize(
|
||||
viewportSize: const Size(600, 600),
|
||||
@@ -46,9 +40,7 @@ Future<void> testMain() async {
|
||||
}
|
||||
recordingCanvas.endRecording();
|
||||
recordingCanvas.apply(canvas, screenRect);
|
||||
if (!isIosSafari) {
|
||||
return scuba.diffCanvasScreenshot(canvas, 'text_with_placeholders');
|
||||
}
|
||||
return scuba.diffCanvasScreenshot(canvas, 'text_with_placeholders');
|
||||
});
|
||||
|
||||
testEachCanvas('text alignment and placeholders', (EngineCanvas canvas) {
|
||||
@@ -85,10 +77,6 @@ Future<void> testMain() async {
|
||||
});
|
||||
}
|
||||
|
||||
const Color black = Color(0xFF000000);
|
||||
const Color blue = Color(0xFF0000FF);
|
||||
const Color red = Color(0xFFFF0000);
|
||||
|
||||
const Size placeholderSize = Size(80.0, 50.0);
|
||||
|
||||
void _paintTextWithPlaceholder(
|
||||
|
||||
@@ -10,6 +10,8 @@ import 'package:ui/ui.dart' as ui;
|
||||
|
||||
import 'package:web_engine_tester/golden_tester.dart';
|
||||
|
||||
import 'helper.dart';
|
||||
|
||||
/// Class that controls some details of how screenshotting is made.
|
||||
///
|
||||
/// (For Googlers: Not really related with internal Scuba anymore)
|
||||
@@ -85,8 +87,6 @@ class EngineScubaTester {
|
||||
}
|
||||
}
|
||||
|
||||
typedef CanvasTest = FutureOr<void> Function(EngineCanvas canvas);
|
||||
|
||||
/// Runs the given test [body] with each type of canvas.
|
||||
void testEachCanvas(String description, CanvasTest body) {
|
||||
const ui.Rect bounds = ui.Rect.fromLTWH(0, 0, 600, 800);
|
||||
|
||||
@@ -9,10 +9,6 @@ import 'package:ui/ui.dart';
|
||||
|
||||
import '../html/paragraph/helper.dart';
|
||||
|
||||
bool get isIosSafari =>
|
||||
browserEngine == BrowserEngine.webkit &&
|
||||
operatingSystem == OperatingSystem.iOs;
|
||||
|
||||
/// Some text measurements are sensitive to browser implementations. Position
|
||||
/// info in the following tests only pass in Chrome, they are slightly different
|
||||
/// on each browser. So we need to ignore position info on non-Chrome browsers
|
||||
@@ -67,7 +63,7 @@ Future<void> testMain() async {
|
||||
|
||||
final CanvasParagraph paragraph = builder.build();
|
||||
expect(paragraph.paragraphStyle, style);
|
||||
expect(paragraph.toPlainText(), 'Hello');
|
||||
expect(paragraph.plainText, 'Hello');
|
||||
expect(paragraph.spans, hasLength(1));
|
||||
|
||||
paragraph.layout(const ParagraphConstraints(width: double.infinity));
|
||||
@@ -97,10 +93,8 @@ Future<void> testMain() async {
|
||||
);
|
||||
|
||||
final ParagraphSpan span = paragraph.spans.single;
|
||||
expect(span, isA<FlatTextSpan>());
|
||||
final FlatTextSpan textSpan = span as FlatTextSpan;
|
||||
expect(textSpan.textOf(paragraph), 'Hello');
|
||||
expect(textSpan.style, styleWithDefaults(fontSize: 13.0));
|
||||
expect(getSpanText(paragraph, span), 'Hello');
|
||||
expect(span.style, styleWithDefaults(fontSize: 13.0));
|
||||
});
|
||||
|
||||
test('Correct defaults', () {
|
||||
@@ -111,7 +105,7 @@ Future<void> testMain() async {
|
||||
|
||||
final CanvasParagraph paragraph = builder.build();
|
||||
expect(paragraph.paragraphStyle, style);
|
||||
expect(paragraph.toPlainText(), 'Hello');
|
||||
expect(paragraph.plainText, 'Hello');
|
||||
expect(paragraph.spans, hasLength(1));
|
||||
|
||||
paragraph.layout(const ParagraphConstraints(width: double.infinity));
|
||||
@@ -125,8 +119,8 @@ Future<void> testMain() async {
|
||||
ignorePositions: !isBlink,
|
||||
);
|
||||
|
||||
final FlatTextSpan textSpan = paragraph.spans.single as FlatTextSpan;
|
||||
expect(textSpan.style, styleWithDefaults());
|
||||
final ParagraphSpan span = paragraph.spans.single;
|
||||
expect(span.style, styleWithDefaults());
|
||||
});
|
||||
|
||||
test('Sets correct styles for max-lines', () {
|
||||
@@ -137,7 +131,7 @@ Future<void> testMain() async {
|
||||
|
||||
final CanvasParagraph paragraph = builder.build();
|
||||
expect(paragraph.paragraphStyle, style);
|
||||
expect(paragraph.toPlainText(), 'Hello');
|
||||
expect(paragraph.plainText, 'Hello');
|
||||
|
||||
paragraph.layout(const ParagraphConstraints(width: double.infinity));
|
||||
expectOuterHtml(
|
||||
@@ -159,7 +153,7 @@ Future<void> testMain() async {
|
||||
|
||||
final CanvasParagraph paragraph = builder.build();
|
||||
expect(paragraph.paragraphStyle, style);
|
||||
expect(paragraph.toPlainText(), 'HelloWorld');
|
||||
expect(paragraph.plainText, 'HelloWorld');
|
||||
|
||||
paragraph.layout(const ParagraphConstraints(width: 100.0));
|
||||
expectOuterHtml(
|
||||
@@ -190,7 +184,7 @@ Future<void> testMain() async {
|
||||
builder.addText('Hello');
|
||||
|
||||
final CanvasParagraph paragraph = builder.build();
|
||||
expect(paragraph.toPlainText(), 'Hello');
|
||||
expect(paragraph.plainText, 'Hello');
|
||||
expect(paragraph.spans, hasLength(1));
|
||||
|
||||
paragraph.layout(const ParagraphConstraints(width: double.infinity));
|
||||
@@ -204,8 +198,8 @@ Future<void> testMain() async {
|
||||
ignorePositions: !isBlink,
|
||||
);
|
||||
|
||||
final FlatTextSpan span = paragraph.spans.single as FlatTextSpan;
|
||||
expect(span.textOf(paragraph), 'Hello');
|
||||
final ParagraphSpan span = paragraph.spans.single;
|
||||
expect(getSpanText(paragraph, span), 'Hello');
|
||||
expect(
|
||||
span.style,
|
||||
styleWithDefaults(
|
||||
@@ -229,7 +223,7 @@ Future<void> testMain() async {
|
||||
builder.addText(' world');
|
||||
|
||||
final CanvasParagraph paragraph = builder.build();
|
||||
expect(paragraph.toPlainText(), 'Hello world');
|
||||
expect(paragraph.plainText, 'Hello world');
|
||||
expect(paragraph.spans, hasLength(2));
|
||||
|
||||
paragraph.layout(const ParagraphConstraints(width: double.infinity));
|
||||
@@ -267,8 +261,8 @@ Future<void> testMain() async {
|
||||
ignorePositions: !isBlink,
|
||||
);
|
||||
|
||||
final FlatTextSpan hello = paragraph.spans.first as FlatTextSpan;
|
||||
expect(hello.textOf(paragraph), 'Hello');
|
||||
final ParagraphSpan hello = paragraph.spans.first;
|
||||
expect(getSpanText(paragraph, hello), 'Hello');
|
||||
expect(
|
||||
hello.style,
|
||||
styleWithDefaults(
|
||||
@@ -277,8 +271,8 @@ Future<void> testMain() async {
|
||||
),
|
||||
);
|
||||
|
||||
final FlatTextSpan world = paragraph.spans.last as FlatTextSpan;
|
||||
expect(world.textOf(paragraph), ' world');
|
||||
final ParagraphSpan world = paragraph.spans.last;
|
||||
expect(getSpanText(paragraph, world), ' world');
|
||||
expect(
|
||||
world.style,
|
||||
styleWithDefaults(
|
||||
@@ -302,7 +296,7 @@ Future<void> testMain() async {
|
||||
builder.addText('!');
|
||||
|
||||
final CanvasParagraph paragraph = builder.build();
|
||||
expect(paragraph.toPlainText(), 'Hello world!');
|
||||
expect(paragraph.plainText, 'Hello world!');
|
||||
expect(paragraph.spans, hasLength(3));
|
||||
|
||||
paragraph.layout(const ParagraphConstraints(width: double.infinity));
|
||||
@@ -325,8 +319,8 @@ Future<void> testMain() async {
|
||||
ignorePositions: !isBlink,
|
||||
);
|
||||
|
||||
final FlatTextSpan hello = paragraph.spans[0] as FlatTextSpan;
|
||||
expect(hello.textOf(paragraph), 'Hello');
|
||||
final ParagraphSpan hello = paragraph.spans[0];
|
||||
expect(getSpanText(paragraph, hello), 'Hello');
|
||||
expect(
|
||||
hello.style,
|
||||
styleWithDefaults(
|
||||
@@ -336,8 +330,8 @@ Future<void> testMain() async {
|
||||
),
|
||||
);
|
||||
|
||||
final FlatTextSpan world = paragraph.spans[1] as FlatTextSpan;
|
||||
expect(world.textOf(paragraph), ' world');
|
||||
final ParagraphSpan world = paragraph.spans[1];
|
||||
expect(getSpanText(paragraph, world), ' world');
|
||||
expect(
|
||||
world.style,
|
||||
styleWithDefaults(
|
||||
@@ -347,8 +341,8 @@ Future<void> testMain() async {
|
||||
),
|
||||
);
|
||||
|
||||
final FlatTextSpan bang = paragraph.spans[2] as FlatTextSpan;
|
||||
expect(bang.textOf(paragraph), '!');
|
||||
final ParagraphSpan bang = paragraph.spans[2];
|
||||
expect(getSpanText(paragraph, bang), '!');
|
||||
expect(
|
||||
bang.style,
|
||||
styleWithDefaults(
|
||||
@@ -368,7 +362,7 @@ Future<void> testMain() async {
|
||||
builder.addText('ThirdLongLine');
|
||||
|
||||
final CanvasParagraph paragraph = builder.build();
|
||||
expect(paragraph.toPlainText(), 'First\nSecond ThirdLongLine');
|
||||
expect(paragraph.plainText, 'First\nSecond ThirdLongLine');
|
||||
expect(paragraph.spans, hasLength(2));
|
||||
|
||||
// There's a new line between "First" and "Second", but "Second" and
|
||||
@@ -430,7 +424,7 @@ Future<void> testMain() async {
|
||||
builder.addText('Third');
|
||||
|
||||
final CanvasParagraph paragraph = builder.build();
|
||||
expect(paragraph.toPlainText(), 'First Second Third');
|
||||
expect(paragraph.plainText, 'First Second Third');
|
||||
expect(paragraph.spans, hasLength(3));
|
||||
|
||||
// The paragraph should take the font size and family from the span with the
|
||||
|
||||
@@ -9,21 +9,6 @@ import 'package:ui/ui.dart' as ui;
|
||||
|
||||
import '../html/paragraph/helper.dart';
|
||||
|
||||
const ui.Color white = ui.Color(0xFFFFFFFF);
|
||||
const ui.Color black = ui.Color(0xFF000000);
|
||||
const ui.Color red = ui.Color(0xFFFF0000);
|
||||
const ui.Color green = ui.Color(0xFF00FF00);
|
||||
const ui.Color blue = ui.Color(0xFF0000FF);
|
||||
|
||||
final EngineParagraphStyle ahemStyle = EngineParagraphStyle(
|
||||
fontFamily: 'ahem',
|
||||
fontSize: 10,
|
||||
);
|
||||
|
||||
ui.ParagraphConstraints constrain(double width) {
|
||||
return ui.ParagraphConstraints(width: width);
|
||||
}
|
||||
|
||||
void main() {
|
||||
internalBootstrapBrowserTest(() => testMain);
|
||||
}
|
||||
|
||||
@@ -207,21 +207,19 @@ Future<void> testMain() async {
|
||||
},
|
||||
);
|
||||
|
||||
final String placeholderChar = String.fromCharCode(0xFFFC);
|
||||
|
||||
expect(split(paragraph), <_Fragment>[
|
||||
_Fragment(placeholderChar, opportunity, ltr, ffLtr, null),
|
||||
_Fragment(placeholderChar, opportunity, ltr, ffLtr, style1),
|
||||
_Fragment('Lorem', opportunity, ltr, ffLtr, style1),
|
||||
_Fragment(placeholderChar, opportunity, ltr, ffLtr, null),
|
||||
_Fragment(placeholderChar, opportunity, ltr, ffLtr, style1),
|
||||
_Fragment('ipsum', prohibited, ltr, ffLtr, style1),
|
||||
_Fragment('\n', mandatory, null, ffSandwich, style1, nl: 1, sp: 1),
|
||||
_Fragment(placeholderChar, opportunity, ltr, ffLtr, null),
|
||||
_Fragment(placeholderChar, opportunity, ltr, ffLtr, style1),
|
||||
_Fragment(rtlWord1, prohibited, rtl, ffRtl, style2),
|
||||
_Fragment(' ', opportunity, null, ffSandwich, style2, sp: 1),
|
||||
_Fragment(placeholderChar, prohibited, ltr, ffLtr, null),
|
||||
_Fragment(placeholderChar, prohibited, ltr, ffLtr, style2),
|
||||
_Fragment('\n', mandatory, null, ffSandwich, style2, nl: 1, sp: 1),
|
||||
_Fragment('sit', opportunity, ltr, ffLtr, style2),
|
||||
_Fragment(placeholderChar, endOfText, ltr, ffLtr, null),
|
||||
_Fragment(placeholderChar, endOfText, ltr, ffLtr, defaultStyle),
|
||||
]);
|
||||
});
|
||||
});
|
||||
@@ -235,13 +233,12 @@ class _Fragment {
|
||||
});
|
||||
|
||||
factory _Fragment._fromLayoutFragment(String text, LayoutFragment layoutFragment) {
|
||||
final ParagraphSpan span = layoutFragment.span;
|
||||
return _Fragment(
|
||||
text.substring(layoutFragment.start, layoutFragment.end),
|
||||
layoutFragment.type,
|
||||
layoutFragment.textDirection,
|
||||
layoutFragment.fragmentFlow,
|
||||
span is FlatTextSpan ? span.style : null,
|
||||
layoutFragment.style,
|
||||
nl: layoutFragment.trailingNewlines,
|
||||
sp: layoutFragment.trailingSpaces,
|
||||
);
|
||||
@@ -251,7 +248,7 @@ class _Fragment {
|
||||
final LineBreakType type;
|
||||
final TextDirection? textDirection;
|
||||
final FragmentFlow fragmentFlow;
|
||||
final EngineTextStyle? style;
|
||||
final EngineTextStyle style;
|
||||
|
||||
/// The number of trailing new line characters.
|
||||
final int nl;
|
||||
|
||||
@@ -7,32 +7,11 @@ import 'package:test/test.dart';
|
||||
import 'package:ui/src/engine.dart';
|
||||
import 'package:ui/ui.dart' as ui;
|
||||
|
||||
import '../html/paragraph/helper.dart';
|
||||
import 'layout_service_helper.dart';
|
||||
|
||||
const bool skipWordSpacing = true;
|
||||
|
||||
final EngineParagraphStyle ahemStyle = EngineParagraphStyle(
|
||||
fontFamily: 'ahem',
|
||||
fontSize: 10,
|
||||
);
|
||||
|
||||
ui.ParagraphConstraints constrain(double width) {
|
||||
return ui.ParagraphConstraints(width: width);
|
||||
}
|
||||
|
||||
CanvasParagraph plain(
|
||||
EngineParagraphStyle style,
|
||||
String text, {
|
||||
EngineTextStyle? textStyle,
|
||||
}) {
|
||||
final CanvasParagraphBuilder builder = CanvasParagraphBuilder(style);
|
||||
if (textStyle != null) {
|
||||
builder.pushStyle(textStyle);
|
||||
}
|
||||
builder.addText(text);
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
void main() {
|
||||
internalBootstrapBrowserTest(() => testMain);
|
||||
}
|
||||
|
||||
@@ -11,19 +11,6 @@ import 'package:ui/ui.dart' as ui;
|
||||
import '../html/paragraph/helper.dart';
|
||||
import 'layout_service_helper.dart';
|
||||
|
||||
final String placeholderChar = String.fromCharCode(0xFFFC);
|
||||
|
||||
const ui.Color white = ui.Color(0xFFFFFFFF);
|
||||
const ui.Color black = ui.Color(0xFF000000);
|
||||
const ui.Color red = ui.Color(0xFFFF0000);
|
||||
const ui.Color green = ui.Color(0xFF00FF00);
|
||||
const ui.Color blue = ui.Color(0xFF0000FF);
|
||||
|
||||
final EngineParagraphStyle ahemStyle = EngineParagraphStyle(
|
||||
fontFamily: 'ahem',
|
||||
fontSize: 10,
|
||||
);
|
||||
|
||||
void main() {
|
||||
internalBootstrapBrowserTest(() => testMain);
|
||||
}
|
||||
|
||||
@@ -12,8 +12,6 @@ import '../html/paragraph/helper.dart';
|
||||
import 'line_breaker_test_helper.dart';
|
||||
import 'line_breaker_test_raw_data.dart';
|
||||
|
||||
final String placeholderChar = String.fromCharCode(0xFFFC);
|
||||
|
||||
void main() {
|
||||
internalBootstrapBrowserTest(() => testMain);
|
||||
}
|
||||
@@ -237,7 +235,7 @@ void testMain() {
|
||||
|
||||
final String placeholderChar = String.fromCharCode(0xFFFC);
|
||||
|
||||
expect(splitParagraph(paragraph), <Line>[
|
||||
expect(split(paragraph.plainText), <Line>[
|
||||
Line(placeholderChar, opportunity),
|
||||
Line('Lorem', opportunity),
|
||||
Line(placeholderChar, opportunity),
|
||||
@@ -260,7 +258,7 @@ void testMain() {
|
||||
|
||||
final String placeholderChar = String.fromCharCode(0xFFFC);
|
||||
|
||||
expect(splitParagraph(paragraph), <Line>[
|
||||
expect(split(paragraph.plainText), <Line>[
|
||||
Line(placeholderChar, endOfText),
|
||||
]);
|
||||
});
|
||||
@@ -279,7 +277,7 @@ void testMain() {
|
||||
},
|
||||
);
|
||||
|
||||
expect(splitParagraph(paragraph), <Line>[
|
||||
expect(split(paragraph.plainText), <Line>[
|
||||
Line('$placeholderChar ', opportunity, sp: 2),
|
||||
Line('Lorem ', opportunity, sp: 2),
|
||||
Line('$placeholderChar \n', mandatory, nl: 1, sp: 3),
|
||||
@@ -456,10 +454,3 @@ List<Line> split(String text) {
|
||||
Line.fromLineBreakFragment(text, fragment)
|
||||
];
|
||||
}
|
||||
|
||||
List<Line> splitParagraph(CanvasParagraph paragraph) {
|
||||
return <Line>[
|
||||
for (final LineBreakFragment fragment in LineBreakFragmenter(paragraph.plainText).fragment())
|
||||
Line.fromLineBreakFragment(paragraph.toPlainText(), fragment)
|
||||
];
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user