Skip to content

Commit

Permalink
Support xlink:href on gradients
Browse files Browse the repository at this point in the history
  • Loading branch information
dnfield committed Jan 14, 2019
1 parent c75f423 commit dd44ee7
Show file tree
Hide file tree
Showing 9 changed files with 301 additions and 151 deletions.
10 changes: 10 additions & 0 deletions example/assets/simple/linear_gradient_xlink.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
8 changes: 4 additions & 4 deletions example/assets/simple/radial_gradient.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
24 changes: 24 additions & 0 deletions example/assets/simple/radial_gradient_xlink.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added golden/simple/linear_gradient_xlink.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added golden/simple/radial_gradient_xlink.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
238 changes: 106 additions & 132 deletions lib/src/svg/parser_state.dart
Original file line number Diff line number Diff line change
Expand Up @@ -186,69 +186,63 @@ class _Elements {

final List<double> offsets = <double>[];
final List<Color> colors = <Color>[];
parseStops(parserState._reader, colors, offsets);

final Rect rootBounds = Rect.fromLTRB(
parserState.rootBounds.left,
parserState.rootBounds.top,
parserState.rootBounds.right,
parserState.rootBounds.bottom,
);

final PaintServer shaderFunc = (Rect bounds) {
double cx, cy, r, fx, fy;
Matrix4 transform = originalTransform?.clone() ?? Matrix4.identity();

if (isObjectBoundingBox) {
final Matrix4 scale =
affineMatrix(bounds.width, 0.0, 0.0, bounds.height, 0.0, 0.0);
final Matrix4 translate =
affineMatrix(1.0, 0.0, 0.0, 1.0, bounds.left, bounds.top);
transform = translate.multiplied(scale)..multiply(transform);

cx = parseDecimalOrPercentage(rawCx);
cy = parseDecimalOrPercentage(rawCy);
r = parseDecimalOrPercentage(rawR);
fx = parseDecimalOrPercentage(rawFx);
fy = parseDecimalOrPercentage(rawFy);
} else {
cx = isPercentage(rawCx)
? parsePercentage(rawCx) * rootBounds.width + rootBounds.left
: double.parse(rawCx);
cy = isPercentage(rawCy)
? parsePercentage(rawCy) * rootBounds.height + rootBounds.top
: double.parse(rawCy);
r = isPercentage(rawR)
? parsePercentage(rawR) *
((rootBounds.height + rootBounds.width) / 2)
: double.parse(rawR);
fx = isPercentage(rawFx)
? parsePercentage(rawFx) * rootBounds.width + rootBounds.left
: double.parse(rawFx);
fy = isPercentage(rawFy)
? parsePercentage(rawFy) * rootBounds.height + rootBounds.top
: double.parse(rawFy);
}
if (parserState._reader.isEmptyElement) {
final String href = getHrefAttribute(parserState.attributes);
final DrawableRadialGradient ref = parserState.definitions
.getGradient<DrawableRadialGradient>('url($href)');
colors.addAll(ref.colors);
offsets.addAll(ref.offsets);
} else {
parseStops(parserState._reader, colors, offsets);
}

final Offset center = Offset(cx, cy);
final Offset focal =
(fx != cx || fy != cy) ? Offset(fx, fy) : Offset(cx, cy);

return Gradient.radial(
center,
r,
colors,
offsets,
spreadMethod,
transform?.storage,
focal,
0.0,
);
};
double cx, cy, r, fx, fy;
if (isObjectBoundingBox) {
cx = parseDecimalOrPercentage(rawCx);
cy = parseDecimalOrPercentage(rawCy);
r = parseDecimalOrPercentage(rawR);
fx = parseDecimalOrPercentage(rawFx);
fy = parseDecimalOrPercentage(rawFy);
} else {
cx = isPercentage(rawCx)
? parsePercentage(rawCx) * parserState.rootBounds.width +
parserState.rootBounds.left
: double.parse(rawCx);
cy = isPercentage(rawCy)
? parsePercentage(rawCy) * parserState.rootBounds.height +
parserState.rootBounds.top
: double.parse(rawCy);
r = isPercentage(rawR)
? parsePercentage(rawR) *
((parserState.rootBounds.height + parserState.rootBounds.width) /
2)
: double.parse(rawR);
fx = isPercentage(rawFx)
? parsePercentage(rawFx) * parserState.rootBounds.width +
parserState.rootBounds.left
: double.parse(rawFx);
fy = isPercentage(rawFy)
? parsePercentage(rawFy) * parserState.rootBounds.height +
parserState.rootBounds.top
: double.parse(rawFy);
}

parserState.definitions.addPaintServer(
parserState.definitions.addGradient(
id,
shaderFunc,
DrawableRadialGradient(
center: Offset(cx, cy),
radius: r,
focal: (fx != cx || fy != cy) ? Offset(fx, fy) : Offset(cx, cy),
focalRadius: 0.0,
colors: colors,
offsets: offsets,
unitMode: isObjectBoundingBox
? GradientUnitMode.objectBoundingBox
: GradientUnitMode.userSpaceOnUse,
spreadMethod: spreadMethod,
transform: originalTransform?.storage,
),
);
return null;
}
Expand All @@ -271,85 +265,65 @@ class _Elements {

final List<Color> colors = <Color>[];
final List<double> offsets = <double>[];
parseStops(parserState._reader, colors, offsets);
final Rect rootBounds = Rect.fromLTRB(
parserState.rootBounds.left,
parserState.rootBounds.top,
parserState.rootBounds.right,
parserState.rootBounds.bottom,
);

final PaintServer shaderFunc = (Rect bounds) {
Vector3 from, to;
Matrix4 transform = originalTransform?.clone() ?? Matrix4.identity();

if (isObjectBoundingBox) {
final Matrix4 scale =
affineMatrix(bounds.width, 0.0, 0.0, bounds.height, 0.0, 0.0);
final Matrix4 translate =
affineMatrix(1.0, 0.0, 0.0, 1.0, bounds.left, bounds.top);
transform = translate.multiplied(scale)..multiply(transform);

final Offset fromOffset = Offset(
parseDecimalOrPercentage(x1),
parseDecimalOrPercentage(y1),
);
final Offset toOffset = Offset(
parseDecimalOrPercentage(x2),
parseDecimalOrPercentage(y2),
);

from = Vector3(
fromOffset.dx,
fromOffset.dy,
0.0,
);
to = Vector3(
toOffset.dx,
toOffset.dy,
0.0,
);
} else {
final Offset fromOffset = Offset(
isPercentage(x1)
? parsePercentage(x1) * rootBounds.width + rootBounds.left
: double.parse(x1),
isPercentage(y1)
? parsePercentage(y1) * rootBounds.height + rootBounds.top
: double.parse(y1),
);

final Offset toOffset = Offset(
isPercentage(x2)
? parsePercentage(x2) * rootBounds.width + rootBounds.left
: double.parse(x2),
isPercentage(y2)
? parsePercentage(y2) * rootBounds.height + rootBounds.top
: double.parse(y2),
);

from = Vector3(fromOffset.dx, fromOffset.dy, 0.0);
to = Vector3(toOffset.dx, toOffset.dy, 0.0);
}
if (parserState._reader.isEmptyElement) {
final String href = getHrefAttribute(parserState.attributes);
final DrawableLinearGradient ref = parserState.definitions
.getGradient<DrawableLinearGradient>('url($href)');
colors.addAll(ref.colors);
offsets.addAll(ref.offsets);
} else {
parseStops(parserState._reader, colors, offsets);
}

if (transform != null) {
from = transform.transform3(from);
to = transform.transform3(to);
}
Offset fromOffset, toOffset;
if (isObjectBoundingBox) {
fromOffset = Offset(
parseDecimalOrPercentage(x1),
parseDecimalOrPercentage(y1),
);
toOffset = Offset(
parseDecimalOrPercentage(x2),
parseDecimalOrPercentage(y2),
);
} else {
fromOffset = Offset(
isPercentage(x1)
? parsePercentage(x1) * parserState.rootBounds.width +
parserState.rootBounds.left
: double.parse(x1),
isPercentage(y1)
? parsePercentage(y1) * parserState.rootBounds.height +
parserState.rootBounds.top
: double.parse(y1),
);

return Gradient.linear(
Offset(from.x, from.y),
Offset(to.x, to.y),
colors,
offsets,
spreadMethod,
toOffset = Offset(
isPercentage(x2)
? parsePercentage(x2) * parserState.rootBounds.width +
parserState.rootBounds.left
: double.parse(x2),
isPercentage(y2)
? parsePercentage(y2) * parserState.rootBounds.height +
parserState.rootBounds.top
: double.parse(y2),
);
};
}

parserState.definitions.addPaintServer(
parserState.definitions.addGradient(
id,
shaderFunc,
DrawableLinearGradient(
from: fromOffset,
to: toOffset,
colors: colors,
offsets: offsets,
spreadMethod: spreadMethod,
unitMode: isObjectBoundingBox
? GradientUnitMode.objectBoundingBox
: GradientUnitMode.userSpaceOnUse,
transform: originalTransform?.storage,
),
);

return null;
}

Expand Down
6 changes: 4 additions & 2 deletions lib/src/svg/parsers.dart
Original file line number Diff line number Diff line change
Expand Up @@ -216,8 +216,10 @@ Future<Image> resolveImage(String href) async {

// eventually this can be const, but not while we have to support
// older Flutter versions
final ParagraphConstraints _infiniteParagraphConstraints =
ParagraphConstraints(width: double.infinity); // ignore: prefer_const_constructors
// ignore: prefer_const_constructors
final ParagraphConstraints _infiniteParagraphConstraints = ParagraphConstraints(
width: double.infinity,
);
const DrawablePaint transparentStroke =
DrawablePaint(PaintingStyle.stroke, color: Color(0x0));
Paragraph createParagraph(
Expand Down
2 changes: 1 addition & 1 deletion lib/src/svg/xml_parsers.dart
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ double parseOpacity(List<XmlAttribute> attributes) {
DrawablePaint _getDefinitionPaint(PaintingStyle paintingStyle, String iri,
DrawableDefinitionServer definitions, Rect bounds,
{double opacity}) {
final Shader shader = definitions.getPaint(iri, bounds);
final Shader shader = definitions.getShader(iri, bounds);
if (shader == null) {
FlutterError.onError(
FlutterErrorDetails(
Expand Down
Loading

0 comments on commit dd44ee7

Please sign in to comment.