Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 7 additions & 11 deletions lib/web_ui/lib/src/engine/canvaskit/canvaskit_api.dart
Original file line number Diff line number Diff line change
Expand Up @@ -1470,7 +1470,13 @@ class SkParagraphBuilder {
external void pushPaintStyle(
SkTextStyle textStyle, SkPaint foreground, SkPaint background);
external void pop();
external void addPlaceholder(SkPlaceholderStyleProperties placeholderStyle);
external void addPlaceholder(
double width,
double height,
SkPlaceholderAlignment alignment,
SkTextBaseline baseline,
double offset,
);
external SkParagraph build();
external void delete();
}
Expand Down Expand Up @@ -1606,16 +1612,6 @@ class SkStrutStyleProperties {
external set forceStrutHeight(bool? value);
}

@JS()
@anonymous
class SkPlaceholderStyleProperties {
external set width(double? value);
external set height(double? value);
external set alignment(SkPlaceholderAlignment? value);
external set offset(double? value);
external set baseline(SkTextBaseline? value);
}

@JS()
@anonymous
class SkFontStyle {
Expand Down
47 changes: 35 additions & 12 deletions lib/web_ui/lib/src/engine/canvaskit/text.dart
Original file line number Diff line number Diff line change
Expand Up @@ -629,7 +629,7 @@ class CkParagraphBuilder implements ui.ParagraphBuilder {

_placeholderCount++;
_placeholderScales.add(scale);
SkPlaceholderStyleProperties placeholderStyle = toSkPlaceholderStyle(
final _CkParagraphPlaceholder placeholderStyle = toSkPlaceholderStyle(
width * scale,
height * scale,
alignment,
Expand All @@ -639,24 +639,31 @@ class CkParagraphBuilder implements ui.ParagraphBuilder {
_addPlaceholder(placeholderStyle);
}

void _addPlaceholder(SkPlaceholderStyleProperties placeholderStyle) {
void _addPlaceholder(_CkParagraphPlaceholder placeholderStyle) {
_commands.add(_ParagraphCommand.addPlaceholder(placeholderStyle));
_paragraphBuilder.addPlaceholder(placeholderStyle);
_paragraphBuilder.addPlaceholder(
placeholderStyle.width,
placeholderStyle.height,
placeholderStyle.alignment,
placeholderStyle.baseline,
placeholderStyle.offset,
);
}

static SkPlaceholderStyleProperties toSkPlaceholderStyle(
static _CkParagraphPlaceholder toSkPlaceholderStyle(
double width,
double height,
ui.PlaceholderAlignment alignment,
double baselineOffset,
ui.TextBaseline baseline,
) {
final properties = SkPlaceholderStyleProperties();
properties.width = width;
properties.height = height;
properties.alignment = toSkPlaceholderAlignment(alignment);
properties.offset = baselineOffset;
properties.baseline = toSkTextBaseline(baseline);
final properties = _CkParagraphPlaceholder(
width: width,
height: height,
alignment: toSkPlaceholderAlignment(alignment),
offset: baselineOffset,
baseline: toSkTextBaseline(baseline),
);
return properties;
}

Expand Down Expand Up @@ -722,11 +729,27 @@ class CkParagraphBuilder implements ui.ParagraphBuilder {
}
}

class _CkParagraphPlaceholder {
_CkParagraphPlaceholder({
required this.width,
required this.height,
required this.alignment,
required this.baseline,
required this.offset,
});

final double width;
final double height;
final SkPlaceholderAlignment alignment;
final SkTextBaseline baseline;
final double offset;
}

class _ParagraphCommand {
final _ParagraphCommandType type;
final String? text;
final CkTextStyle? style;
final SkPlaceholderStyleProperties? placeholderStyle;
final _CkParagraphPlaceholder? placeholderStyle;

const _ParagraphCommand._(
this.type,
Expand All @@ -745,7 +768,7 @@ class _ParagraphCommand {
: this._(_ParagraphCommandType.pushStyle, null, style, null);

const _ParagraphCommand.addPlaceholder(
SkPlaceholderStyleProperties placeholderStyle)
_CkParagraphPlaceholder placeholderStyle)
: this._(
_ParagraphCommandType.addPlaceholder, null, null, placeholderStyle);
}
Expand Down
109 changes: 109 additions & 0 deletions lib/web_ui/test/canvaskit/canvaskit_api_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import 'package:test/test.dart';
import 'package:ui/src/engine.dart';
import 'package:ui/ui.dart' as ui;

import '../matchers.dart';
import 'common.dart';
import 'test_data.dart';

Expand Down Expand Up @@ -47,6 +48,7 @@ void testMain() {
_toSkMatrixFromFloat32Tests();
_toSkRectTests();
_skVerticesTests();
_paragraphTests();
group('SkPath', () {
_pathTests();
});
Expand Down Expand Up @@ -1229,3 +1231,110 @@ void _textStyleTests() {
}
});
}

void _paragraphTests() {
// This test is just a kitchen sink that blasts CanvasKit with all paragraph
// properties all at once, making sure CanvasKit doesn't choke on anything.
// In particular, this tests that our JS bindings are correct, such as that
// arguments are of acceptable types and passed in the correct order.
test('SkParagraph API kitchensink', () {
final SkParagraphStyleProperties props = SkParagraphStyleProperties();
props.textAlign = canvasKit.TextAlign.Center;
props.textDirection = canvasKit.TextDirection.RTL;
props.heightMultiplier = 3;
props.textHeightBehavior = ui.TextHeightBehavior().encode();
props.maxLines = 4;
props.ellipsis = '___';
props.textStyle = SkTextStyleProperties()
..backgroundColor = Float32List.fromList(<double>[1, 2, 3, 4])
..color = Float32List.fromList(<double>[5, 6, 7, 8])
..foregroundColor = Float32List.fromList(<double>[9, 10, 11, 12])
..decoration = 0x2
..decorationThickness = 2.0
..decorationColor = Float32List.fromList(<double>[13, 14, 15, 16])
..decorationStyle = canvasKit.DecorationStyle.Dotted
..textBaseline = canvasKit.TextBaseline.Ideographic
..fontSize = 24
..letterSpacing = 5
..wordSpacing = 10
..heightMultiplier = 2.5
..locale = 'en_CA'
..fontFamilies = <String>['Roboto', 'serif']
..fontStyle = (SkFontStyle()
..slant = canvasKit.FontSlant.Upright
..weight = canvasKit.FontWeight.Normal)
..shadows = <SkTextShadow>[]
..fontFeatures = <SkFontFeature>[
SkFontFeature()
..name = 'pnum'
..value = 1,
SkFontFeature()
..name = 'tnum'
..value = 1,
];
props.strutStyle = SkStrutStyleProperties()
..fontFamilies = <String>['Roboto', 'Noto']
..fontStyle = (SkFontStyle()
..slant = canvasKit.FontSlant.Italic
..weight = canvasKit.FontWeight.Bold)
..fontSize = 23
..heightMultiplier = 5
..leading = 6
..strutEnabled = true
..forceStrutHeight = false;

final SkParagraphStyle paragraphStyle = canvasKit.ParagraphStyle(props);
final SkParagraphBuilder builder = canvasKit.ParagraphBuilder.Make(
paragraphStyle,
skiaFontCollection.skFontMgr,
);

builder.addText('Hello');
builder.addPlaceholder(
50,
25,
canvasKit.PlaceholderAlignment.Middle,
canvasKit.TextBaseline.Ideographic,
4.0,
);
builder.pushStyle(canvasKit.TextStyle(SkTextStyleProperties()
..fontSize = 12));
builder.addText('World');
builder.pop();
builder.pushPaintStyle(canvasKit.TextStyle(SkTextStyleProperties()
..fontSize = 12), SkPaint(), SkPaint());
builder.addText('!');
builder.pop();
final SkParagraph paragraph = builder.build();
paragraph.layout(55);
expect(paragraph.getAlphabeticBaseline(), within<double>(distance: 0.5, from: 22));
expect(paragraph.didExceedMaxLines(), false);
expect(paragraph.getHeight(), 28);
expect(paragraph.getIdeographicBaseline(), within<double>(distance: 0.5, from: 28));
expect(paragraph.getLongestLine(), 50);
expect(paragraph.getMaxIntrinsicWidth(), 50);
expect(paragraph.getMinIntrinsicWidth(), 0);
expect(paragraph.getMaxWidth(), 55);
expect(paragraph.getRectsForRange(1, 3, canvasKit.RectHeightStyle.Tight, canvasKit.RectWidthStyle.Max), <double>[]);
expect(paragraph.getRectsForPlaceholders(), hasLength(1));
expect(paragraph.getGlyphPositionAtCoordinate(5, 5).affinity, canvasKit.Affinity.Downstream);

// "Hello"
for (int i = 0; i < 5; i++) {
expect(paragraph.getWordBoundary(i).start, 0);
expect(paragraph.getWordBoundary(i).end, 5);
}
// Placeholder
expect(paragraph.getWordBoundary(5).start, 5);
expect(paragraph.getWordBoundary(5).end, 6);
// "World"
for (int i = 6; i < 11; i++) {
expect(paragraph.getWordBoundary(i).start, 6);
expect(paragraph.getWordBoundary(i).end, 11);
}
// "!"
expect(paragraph.getWordBoundary(11).start, 11);
expect(paragraph.getWordBoundary(11).end, 12);
paragraph.delete();
});
}