Skip to content

Commit

Permalink
Text improvements (#95)
Browse files Browse the repository at this point in the history
* text improvements -need goldens

* add golden, clean up analysis
  • Loading branch information
dnfield authored Dec 31, 2018
1 parent 719bd81 commit 7ffb2b9
Show file tree
Hide file tree
Showing 9 changed files with 126 additions and 55 deletions.
21 changes: 13 additions & 8 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
# CHANGES

## 0.9.0+1

- Fix inheritance issues with `text-anchor`.
- Fix a few inconsistencies in text anchor processing/positioning.

## 0.9.0

- **BREAKING** Improvements to text positioning. Thanks to @krispypen!
Expand Down Expand Up @@ -55,7 +60,7 @@
## 0.6.3

- Consume updated version of path_drawing.
- Fix bug with fill-rule inheritence + example to test.
- Fix bug with fill-rule inheritance + example to test.

## 0.6.2

Expand All @@ -64,7 +69,7 @@

## 0.6.1

- Fixed an issue with stroke and fill inheritence (and added test)
- Fixed an issue with stroke and fill inheritance (and added test)
- General formatting/analyzer cleanup

## 0.6.0
Expand All @@ -82,8 +87,8 @@
- Create a new class to encapsulate `Paint` and assist with inheriting all
painting properties.
- Fixes regression introduced in v0.5.2 where some previously working
inheritence stopped working.
- Support more complex stroke/fill property inheritence.
inheritance stopped working.
- Support more complex stroke/fill property inheritance.

## 0.5.4

Expand Down Expand Up @@ -170,7 +175,7 @@

## 0.2.0

- Fix bug(s) in inheritence (better rendering of Ghostscript_Tiger.svg)
- Fix bug(s) in inheritance (better rendering of Ghostscript_Tiger.svg)
- Support for `<clipPath>`s
- Refactoring of how gradients are handled to enable clipPaths
- Refactor of SVG shape -> path logic
Expand All @@ -188,20 +193,20 @@
- Add more unit tests and rendering tests (!).
- Add top level flutter_svg.dart.
- Fix bugs found in transform matrix logic for skewX and skewY.
- Minor improvements in handling inheritence for PathFillType.
- Minor improvements in handling inheritance for PathFillType.
- Support gradient spread types (TileModes in Flutter).

## 0.1.2

- Bump to path_drawing 0.2.3 (fix arc defect).
- Handle 'none' in dasharray without throwing exception.
- Better handling of inheritence and 'none' in fill/stroke/dasharray
- Better handling of inheritance and 'none' in fill/stroke/dasharray

## 0.1.1

- Handle opacity on groups and inherited/blended opacity.
- Fixes elements that have both opacity and stroke-opacity or fill-opacity.
- Improvements for inheritence.
- Improvements for inheritance.
- Fixes related to unspecified fills on shapes.

## 0.1.0
Expand Down
1 change: 0 additions & 1 deletion analysis_options.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,6 @@ linter:
# - parameter_assignments # we do this commonly
- prefer_adjacent_string_concatenation
- prefer_asserts_in_initializer_lists
- prefer_bool_in_asserts
- prefer_collection_literals
- prefer_conditional_assignment
- prefer_const_constructors
Expand Down
11 changes: 11 additions & 0 deletions example/assets/simple/text_3.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion example/pubspec.lock
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ packages:
path: ".."
relative: true
source: path
version: "0.9.0"
version: "0.9.0+1"
meta:
dependency: transitive
description:
Expand Down
Binary file added golden/simple/text_3.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
96 changes: 62 additions & 34 deletions lib/src/svg_parser.dart
Original file line number Diff line number Diff line change
Expand Up @@ -230,8 +230,9 @@ void _appendParagraphs(ParagraphBuilder fill, ParagraphBuilder stroke,

stroke
..pushStyle(style.textStyle.toFlutterTextStyle(
foregroundOverride:
DrawablePaint.isEmpty(style.stroke) ? _transparentStroke : style.stroke))
foregroundOverride: DrawablePaint.isEmpty(style.stroke)
? _transparentStroke
: style.stroke))
..addText(text);
}

Expand All @@ -245,20 +246,20 @@ Paragraph _finishParagraph(ParagraphBuilder paragraphBuilder) {
}

Drawable _paragraphParser(
ParagraphBuilder fill,
ParagraphBuilder stroke,
Offset parentOffset,
DrawableTextAnchorPosition textAnchor,
DrawableDefinitionServer definitions,
Rect bounds,
XmlNode parent,
DrawableStyle style) {
ParagraphBuilder fill,
ParagraphBuilder stroke,
Offset parentOffset,
DrawableDefinitionServer definitions,
Rect bounds,
XmlNode parent,
DrawableStyle style,
) {
final List<Drawable> children = <Drawable>[];
Offset currentOffset = Offset(parentOffset.dx, parentOffset.dy);
for (XmlNode child in parent.children) {
switch (child.nodeType) {
case XmlNodeType.CDATA:
_appendParagraphs(fill, stroke, child.text, style);
_appendParagraphs(fill, stroke, child.text, style);
break;
case XmlNodeType.TEXT:
if (child.text.trim().isNotEmpty) {
Expand All @@ -272,20 +273,35 @@ Drawable _paragraphParser(
final ParagraphBuilder stroke = ParagraphBuilder(ParagraphStyle());
final String x = getAttribute(child, 'x', def: null);
final String y = getAttribute(child, 'y', def: null);
final Offset staticOffset = Offset(x!=null ? double.parse(x) : null,
y!=null ? double.parse(y) : null);
final Offset relativeOffset = Offset(double.parse(getAttribute(child, 'dx', def: '0')),
double.parse(getAttribute(child, 'dy', def: '0')));
final Offset offset = Offset(staticOffset.dx ?? (currentOffset.dx + relativeOffset.dx),
staticOffset.dy ?? (currentOffset.dy + relativeOffset.dy));
final Drawable drawable = _paragraphParser(fill, stroke, offset, textAnchor, definitions,
bounds, child, childStyle);
final Offset staticOffset = Offset(
x != null ? double.parse(x) : null,
y != null ? double.parse(y) : null,
);
final Offset relativeOffset = Offset(
double.parse(getAttribute(child, 'dx', def: '0')),
double.parse(getAttribute(child, 'dy', def: '0')),
);
final Offset offset = Offset(
staticOffset.dx ?? (currentOffset.dx + relativeOffset.dx),
staticOffset.dy ?? (currentOffset.dy + relativeOffset.dy),
);
final Drawable drawable = _paragraphParser(
fill,
stroke,
offset,
definitions,
bounds,
child,
childStyle,
);
fill.pop();
stroke.pop();
children.add(drawable);
if (drawable is DrawableText){
if (drawable is DrawableText) {
drawable.fill.layout(ParagraphConstraints(width: double.infinity));
currentOffset = Offset(currentOffset.dx + drawable.fill.maxIntrinsicWidth, currentOffset.dy);
currentOffset = Offset(
currentOffset.dx + drawable.fill.maxIntrinsicWidth,
currentOffset.dy);
}
break;
default:
Expand All @@ -296,9 +312,10 @@ Drawable _paragraphParser(
_finishParagraph(fill),
_finishParagraph(stroke),
parentOffset,
textAnchor,
style.textStyle.anchor ?? DrawableTextAnchorPosition.start,
transform: style.transform,
));
if (children.length==1){
if (children.length == 1) {
return children.elementAt(0);
}
return DrawableGroup(children, style);
Expand All @@ -309,17 +326,26 @@ Drawable parseSvgText(XmlElement el, DrawableDefinitionServer definitions,
final Offset offset = Offset(double.parse(getAttribute(el, 'x', def: '0')),
double.parse(getAttribute(el, 'y', def: '0')));

final DrawableStyle style = parseStyle(el, definitions, bounds, parentStyle);
final DrawableStyle style = parseStyle(
el,
definitions,
bounds,
parentStyle,
needsTransform: true,
);

final ParagraphBuilder fill = ParagraphBuilder(ParagraphStyle());
final ParagraphBuilder stroke = ParagraphBuilder(ParagraphStyle());

final DrawableTextAnchorPosition textAnchor =
parseTextAnchor(getAttribute(el, 'text-anchor', def: 'start'));

return _paragraphParser(fill, stroke, offset, textAnchor, definitions, bounds, el, style);


return _paragraphParser(
fill,
stroke,
offset,
definitions,
bounds,
el,
style,
);
}

/// Parses an SVG <g> element.
Expand Down Expand Up @@ -374,18 +400,20 @@ DrawableStyle parseStyle(
clipPath: parseClipPath(el, definitions),
textStyle: DrawableTextStyle(
fontFamily: getAttribute(el, 'font-family', def: null),
fontWeight: getFontWeightByName(getAttribute(el, 'font-weight', def: null)),
fontWeight:
getFontWeightByName(getAttribute(el, 'font-weight', def: null)),
fontSize: parseFontSize(getAttribute(el, 'font-size'),
parentValue: parentStyle?.textStyle?.fontSize),
anchor: parseTextAnchor(getAttribute(el, 'text-anchor', def: 'inherit')),
),
);
}

FontWeight getFontWeightByName(String fontWeight){
if (fontWeight==null) {
FontWeight getFontWeightByName(String fontWeight) {
if (fontWeight == null) {
return null;
}
switch(fontWeight){
switch (fontWeight) {
case '100':
return FontWeight.w100;
case '200':
Expand Down
1 change: 1 addition & 0 deletions lib/src/utilities/http.dart
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import 'dart:async';
import 'dart:io';
import 'dart:typed_data';

Expand Down
47 changes: 37 additions & 10 deletions lib/src/vector_drawable.dart
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ class DrawableStyle {
/// Used where 'dasharray' is 'none'
///
/// This will not result in a drawing operation, but will clear out
/// inheritence.
/// inheritance.
static final CircularIntervalList<double> emptyDashArray =
CircularIntervalList<double>(const <double>[]);

Expand Down Expand Up @@ -311,6 +311,7 @@ class DrawableTextStyle {
this.height,
this.locale,
this.textBaseline,
this.anchor,
});

factory DrawableTextStyle.merge(DrawableTextStyle a, DrawableTextStyle b) {
Expand All @@ -335,6 +336,8 @@ class DrawableTextStyle {
locale: a.locale ?? b.locale,
background: a.background ?? b.background,
foreground: a.foreground ?? b.foreground,
// anchor: a.anchor != DrawableTextAnchorPosition.start ? a.anchor ?? b.anchor : b.anchor,
anchor: a.anchor ?? b.anchor,
);
}

Expand All @@ -352,6 +355,7 @@ class DrawableTextStyle {
final Locale locale;
final DrawablePaint background;
final DrawablePaint foreground;
final DrawableTextAnchorPosition anchor;

TextStyle toFlutterTextStyle({DrawablePaint foregroundOverride}) {
return TextStyle(
Expand All @@ -374,22 +378,29 @@ class DrawableTextStyle {
}

@override
String toString() {
return 'DrawableTextStyle{$decoration,$decorationColor,$decorationStyle,$fontWeight,$fontFamily,$fontSize,$fontStyle,$foreground,$background,$letterSpacing,$wordSpacing,$height,$locale,$textBaseline}';
}
String toString() =>
'DrawableTextStyle{$decoration,$decorationColor,$decorationStyle,$fontWeight,'
'$fontFamily,$fontSize,$fontStyle,$foreground,$background,$letterSpacing,$wordSpacing,$height,'
'$locale,$textBaseline,$anchor}';
}

enum DrawableTextAnchorPosition { start, middle, end }

// WIP. This only handles very, very minimal use cases right now.
class DrawableText implements Drawable {
DrawableText(this.fill, this.stroke, this.offset, this.anchor)
: assert(fill != null || stroke != null);
DrawableText(
this.fill,
this.stroke,
this.offset,
this.anchor, {
this.transform,
}) : assert(fill != null || stroke != null);

final Offset offset;
final DrawableTextAnchorPosition anchor;
final Paragraph fill;
final Paragraph stroke;
final Float64List transform;

@override
bool get hasDrawableContent =>
Expand All @@ -400,12 +411,19 @@ class DrawableText implements Drawable {
if (!hasDrawableContent) {
return;
}
if (transform != null) {
canvas.save();
canvas.transform(transform);
}
if (fill != null) {
canvas.drawParagraph(fill, resolveOffset(fill, anchor, offset));
}
if (stroke != null) {
canvas.drawParagraph(stroke, resolveOffset(stroke, anchor, offset));
}
if (transform != null) {
canvas.restore();
}
}

static Offset resolveOffset(
Expand All @@ -418,13 +436,22 @@ class DrawableText implements Drawable {
assert(offset != null);
switch (anchor) {
case DrawableTextAnchorPosition.middle:
return Offset(offset.dx - paragraph.minIntrinsicWidth / 2, offset.dy-paragraph.height);
return Offset(
offset.dx - paragraph.minIntrinsicWidth / 2,
offset.dy - paragraph.alphabeticBaseline,
);
break;
case DrawableTextAnchorPosition.end:
return Offset(offset.dx - paragraph.minIntrinsicWidth, offset.dy-paragraph.height);
return Offset(
offset.dx - paragraph.minIntrinsicWidth,
offset.dy - paragraph.alphabeticBaseline,
);
break;
case DrawableTextAnchorPosition.start:
return Offset(offset.dx, offset.dy-paragraph.alphabeticBaseline);
return Offset(
offset.dx,
offset.dy - paragraph.alphabeticBaseline,
);
break;
default:
return offset;
Expand Down Expand Up @@ -552,7 +579,7 @@ class DrawableRoot implements Drawable {
/// Contains reusable definitions such as gradients and clipPaths.
final DrawableDefinitionServer definitions;

/// The [DrawableStyle] for inheritence.
/// The [DrawableStyle] for inheritance.
final DrawableStyle style;

/// Scales the `canvas` so that the drawing units in this [Drawable]
Expand Down
Loading

0 comments on commit 7ffb2b9

Please sign in to comment.