added support for gradient background size and fixed linear gradient angle when vendor prefix is used

This commit is contained in:
Matthias Christen 2017-12-09 23:07:27 +01:00
parent 9bc0fb0bd1
commit d1e870de88
4 changed files with 97 additions and 11 deletions

View File

@ -34,7 +34,7 @@ export const parseGradient = (
bounds: Bounds bounds: Bounds
): ?Gradient => { ): ?Gradient => {
if (method === 'linear-gradient') { if (method === 'linear-gradient') {
return parseLinearGradient(args, bounds); return parseLinearGradient(args, bounds, !!prefix);
} else if (method === 'gradient' && args[0] === 'linear') { } else if (method === 'gradient' && args[0] === 'linear') {
// TODO handle correct angle // TODO handle correct angle
return parseLinearGradient( return parseLinearGradient(
@ -46,18 +46,23 @@ export const parseGradient = (
// $FlowFixMe // $FlowFixMe
.map(v => v[2]) .map(v => v[2])
), ),
bounds bounds,
!!prefix
); );
} }
}; };
const parseLinearGradient = (args: Array<string>, bounds: Bounds): Gradient => { const parseLinearGradient = (args: Array<string>, bounds: Bounds, hasPrefix: boolean): Gradient => {
const angle = parseAngle(args[0]); const angle = parseAngle(args[0]);
const HAS_SIDE_OR_CORNER = SIDE_OR_CORNER.test(args[0]); const HAS_SIDE_OR_CORNER = SIDE_OR_CORNER.test(args[0]);
const HAS_DIRECTION = HAS_SIDE_OR_CORNER || angle !== null || PERCENTAGE_ANGLES.test(args[0]); const HAS_DIRECTION = HAS_SIDE_OR_CORNER || angle !== null || PERCENTAGE_ANGLES.test(args[0]);
const direction = HAS_DIRECTION const direction = HAS_DIRECTION
? angle !== null ? angle !== null
? calculateGradientDirection(angle, bounds) ? calculateGradientDirection(
// if there is a prefix, the 0° angle points due East (instead of North per W3C)
hasPrefix ? angle - Math.PI * 0.5 : angle,
bounds
)
: HAS_SIDE_OR_CORNER : HAS_SIDE_OR_CORNER
? parseSideOrCorner(args[0], bounds) ? parseSideOrCorner(args[0], bounds)
: parsePercentageAngle(args[0], bounds) : parsePercentageAngle(args[0], bounds)

View File

@ -30,7 +30,8 @@ import {
calculateBackgroungPaintingArea, calculateBackgroungPaintingArea,
calculateBackgroundPosition, calculateBackgroundPosition,
calculateBackgroundRepeatPath, calculateBackgroundRepeatPath,
calculateBackgroundSize calculateBackgroundSize,
calculateGradientBackgroundSize
} from './parsing/background'; } from './parsing/background';
import {BORDER_STYLE} from './parsing/border'; import {BORDER_STYLE} from './parsing/border';
@ -202,12 +203,8 @@ export default class Renderer {
container.style.background.backgroundImage.slice(0).reverse().forEach(backgroundImage => { container.style.background.backgroundImage.slice(0).reverse().forEach(backgroundImage => {
if (backgroundImage.source.method === 'url' && backgroundImage.source.args.length) { if (backgroundImage.source.method === 'url' && backgroundImage.source.args.length) {
this.renderBackgroundRepeat(container, backgroundImage); this.renderBackgroundRepeat(container, backgroundImage);
} else { } else if (/gradient/i.test(backgroundImage.source.method)) {
const gradient = parseGradient(backgroundImage.source, container.bounds); this.renderBackgroundGradient(container, backgroundImage);
if (gradient) {
const bounds = container.bounds;
this.target.renderLinearGradient(bounds, gradient);
}
} }
}); });
} }
@ -245,6 +242,35 @@ export default class Renderer {
} }
} }
renderBackgroundGradient(container: NodeContainer, background: BackgroundImage) {
const backgroundPositioningArea = calculateBackgroungPositioningArea(
container.style.background.backgroundOrigin,
container.bounds,
container.style.padding,
container.style.border
);
const backgroundImageSize = calculateGradientBackgroundSize(
background,
backgroundPositioningArea
);
const position = calculateBackgroundPosition(
background.position,
backgroundImageSize,
backgroundPositioningArea
);
const gradientBounds = new Bounds(
Math.round(backgroundPositioningArea.left + position.x),
Math.round(backgroundPositioningArea.top + position.y),
backgroundImageSize.width,
backgroundImageSize.height
);
const gradient = parseGradient(background.source, gradientBounds);
if (gradient) {
this.target.renderLinearGradient(gradientBounds, gradient);
}
}
renderBorder(border: Border, side: BorderSide, curvePoints: BoundCurves) { renderBorder(border: Border, side: BorderSide, curvePoints: BoundCurves) {
this.target.drawShape(parsePathForBorder(curvePoints, side), border.borderColor); this.target.drawShape(parsePathForBorder(curvePoints, side), border.borderColor);
} }

View File

@ -123,6 +123,19 @@ export const calculateBackgroundSize = (
return new Size(width, height); return new Size(width, height);
}; };
export const calculateGradientBackgroundSize = (
backgroundImage: BackgroundImage,
bounds: Bounds
): Size => {
const size = backgroundImage.size;
const width = size[0].value ? size[0].value.getAbsoluteValue(bounds.width) : bounds.width;
const height = size[1].value
? size[1].value.getAbsoluteValue(bounds.height)
: size[0].value ? width : bounds.height;
return new Size(width, height);
};
const AUTO_SIZE = new BackgroundSize(AUTO); const AUTO_SIZE = new BackgroundSize(AUTO);
export const calculateBackgroungPaintingArea = ( export const calculateBackgroungPaintingArea = (

View File

@ -0,0 +1,42 @@
<!doctype html>
<html>
<head>
<title>Background attribute tests</title>
<script type="text/javascript" src="../../test.js"></script>
<style>
body {
background-color: blanchedalmond;
}
div {
display: inline-block;
width: 100px;
height: 100px;
padding: 10px;
border: 15px solid black;
}
</style>
</head>
<body>
<div style="background: -webkit-linear-gradient(90deg, blue, red);"></div>
<div style="background: linear-gradient(90deg, blue, red);"></div>
<div style="background: linear-gradient(45deg, blue, red);"></div>
<div style="background: linear-gradient(45deg, blue, red); width:200px;"></div>
<div style="background-image: linear-gradient(45deg, blue, red); background-position: 20px 30px; background-size: 60px; background-repeat: no-repeat"></div>
<div style="background-image: linear-gradient(45deg, blue, red); background-position: 20px 30px; background-size: 60px;"></div>
<div style="background-image: linear-gradient(45deg, blue, red);padding:0"></div>
<div style="background: linear-gradient(red, red 60%, blue);"></div>
<div style="background: linear-gradient(90deg, red 60%, blue);"></div>
<div style="background: linear-gradient(135deg, red, red 60%, blue);"></div>
<div style="background: linear-gradient(to right, red, red 60%, blue);"></div>
<div style="background: linear-gradient(to right, red, orange, yellow, green, blue, indigo, violet);"></div>
<div style="background: linear-gradient(60deg, yellow 0%, orange 10%, red 50%, blue 90%, cyan 100%);"></div>
<div style="background: linear-gradient(45deg, yellow 0%, orange 10%, red 50%, blue 90%, cyan 100%); background-origin: content-box"></div>
<div style="background: linear-gradient(90deg, yellow 0%, orange 10%, red 50%, blue 90%, cyan 100%); background-origin: padding-box"></div>
<div style="background: linear-gradient(90deg, yellow 0%, orange 10%, red 50%, blue 90%, cyan 100%); background-origin: border-box"></div>
<div style="background: linear-gradient(to right, rgba(255,255,255,0) 0%,rgba(255,255,255,1) 100%); "></div>
<div style="background: linear-gradient(90deg, yellow 0%, orange 10%, red 50%, blue 90%, cyan 100%) content-box;"></div>
<div style="background: linear-gradient(60deg, hsla(120,80%,50%,0.8) 0%, transparent 50%, rgba(255,100,100,0.5) 100%);"></div>
</body>
</html>