Commit 6062c10e authored by meade's avatar meade Committed by Commit Bot

[CSS Typed OM] Implement FromCSSValue and AsMatrix for CSSTranslation

Spec: https://drafts.css-houdini.org/css-typed-om/#csstranslation

Additionally found during testing:
- Z should not be able to be set to null
- Use new CSS.px(1) syntax for inlinestyle/translation test for brevity

BUG=545318

Review-Url: https://codereview.chromium.org/2961243002
Cr-Commit-Position: refs/heads/master@{#486684}
parent 9fc8b522
<!DOCTYPE html>
<script src="../resources/testharness.js"></script>
<script src="../resources/testharnessreport.js"></script>
<script src="resources/comparisons.js"></script>
<script>
var zeroLength = new CSSUnitValue(0, "px");
var decimalLength = new CSSUnitValue(1.1, "px");
var negativeLength = new CSSUnitValue(-2.2, "em");
var tenPercent = new CSSUnitValue(10, "percent");
let EPSILON = 1e-6;
var testParams = [
// 2D translations
{
input: new CSSTranslation(zeroLength, zeroLength),
x: zeroLength, y: zeroLength,
input: new CSSTranslation(CSS.px(0), CSS.px(0)),
x: CSS.px(0), y: CSS.px(0),
is2D: true,
cssText: "translate(0px, 0px)"
},
{
input: new CSSTranslation(decimalLength, negativeLength),
x: decimalLength, y: negativeLength,
input: new CSSTranslation(CSS.px(1.1), CSS.em(-2.2)),
x: CSS.px(1.1), y: CSS.em(-2.2),
is2D: true,
cssText: "translate(1.1px, -2.2em)"
},
{
input: new CSSTranslation(tenPercent, zeroLength),
x: tenPercent, y: zeroLength,
input: new CSSTranslation(CSS.percent(10), CSS.px(0)),
x: CSS.percent(10), y: CSS.px(0),
is2D: true,
cssText: "translate(10%, 0px)"
},
// 3D translations
{
input: new CSSTranslation(zeroLength, zeroLength, zeroLength),
x: zeroLength, y: zeroLength, z: zeroLength,
input: new CSSTranslation(CSS.px(0), CSS.px(0), CSS.px(0)),
x: CSS.px(0), y: CSS.px(0), z: CSS.px(0),
is2D: false,
cssText: "translate3d(0px, 0px, 0px)"
},
{
input: new CSSTranslation(zeroLength, decimalLength, negativeLength),
x: zeroLength, y: decimalLength, z: negativeLength,
input: new CSSTranslation(CSS.px(0), CSS.px(1.1), CSS.em(-2.2)),
x: CSS.px(0), y: CSS.px(1.1), z: CSS.em(-2.2),
is2D: false,
cssText: "translate3d(0px, 1.1px, -2.2em)"
},
{
input: new CSSTranslation(tenPercent, decimalLength, zeroLength),
x: tenPercent, y: decimalLength, z: zeroLength,
input: new CSSTranslation(CSS.percent(10), CSS.px(1.1), CSS.px(0)),
x: CSS.percent(10), y: CSS.px(1.1), z: CSS.px(0),
is2D: false,
cssText: "translate3d(10%, 1.1px, 0px)"
},
......@@ -52,12 +49,15 @@ var testParams = [
for (let params of testParams) {
test(() => {
assert_equals(params.input.x, params.x);
assert_equals(params.input.y, params.y);
assert_equals(params.input.x.value, params.x.value);
assert_equals(params.input.x.unit, params.x.unit);
assert_equals(params.input.y.value, params.y.value);
assert_equals(params.input.y.unit, params.y.unit);
if (params.is2D) {
assert_equals(params.input.z.value, 0);
} else {
assert_equals(params.input.z, params.z);
assert_equals(params.input.z.value, params.z.value);
assert_equals(params.input.z.unit, params.z.unit);
}
}, "x, y, and z values are correct for " + params.cssText);
......@@ -83,7 +83,7 @@ test(() => {
let translation3d = new CSSTranslation(
new CSSUnitValue(30, 'percent'),
new CSSUnitValue(40, 'percent'),
zeroLength);
CSS.px(0));
assert_equals(translation3d.x.value, 30);
assert_equals(translation3d.x.unit, 'percent');
assert_equals(translation3d.y.value, 40);
......@@ -93,34 +93,34 @@ test(() => {
test(() => {
assert_throws(new TypeError(), () => {
new CSSTranslation(new CSSUnitValue(10, 'deg'), zeroLength);
new CSSTranslation(new CSSUnitValue(10, 'deg'), CSS.px(0));
});
assert_throws(new TypeError(), () => {
new CSSTranslation(zeroLength, new CSSUnitValue(10, 'deg'));
new CSSTranslation(CSS.px(0), new CSSUnitValue(10, 'deg'));
});
assert_throws(new TypeError(), () => {
new CSSTranslation(new CSSUnitValue(10, 'deg'), zeroLength, zeroLength);
new CSSTranslation(new CSSUnitValue(10, 'deg'), CSS.px(0), CSS.px(0));
});
assert_throws(new TypeError(), () => {
new CSSTranslation(zeroLength, new CSSUnitValue(10, 'deg'), zeroLength);
new CSSTranslation(CSS.px(0), new CSSUnitValue(10, 'deg'), CSS.px(0));
});
assert_throws(new TypeError(), () => {
new CSSTranslation(zeroLength, zeroLength, new CSSUnitValue(10, 'deg'));
new CSSTranslation(CSS.px(0), CSS.px(0), new CSSUnitValue(10, 'deg'));
});
}, "Constructor throws when invalid numeric values are given to each argument");
test(() => {
assert_throws(new TypeError(), () => {
new CSSTranslation(zeroLength, zeroLength, tenPercent);
new CSSTranslation(CSS.px(0), CSS.px(0), CSS.percent(10));
});
assert_throws(new TypeError(), () => {
new CSSTranslation(tenPercent, tenPercent, tenPercent);
new CSSTranslation(CSS.percent(10), CSS.percent(10), CSS.percent(10));
});
}, "Constructor throws when z argument contains percent.");
test(() => {
assert_throws(new TypeError(), () => { new CSSTranslation(); });
assert_throws(new TypeError(), () => { new CSSTranslation(zeroLength); });
assert_throws(new TypeError(), () => { new CSSTranslation(CSS.px(0)); });
}, "Invalid number of arguments to constructor throws an exception.");
for (let attribute of ["x", "y"]) {
......@@ -160,20 +160,27 @@ for (let attribute of ["x", "y", "z"]) {
}
test(() => {
let validLength = new CSSUnitValue(5, 'px');
let translation = new CSSTranslation(validLength, validLength, validLength);
assert_equals(translation.z.value, 5);
assert_equals(translation.z.unit, 'px');
translation.z = null;
assert_equals(translation.z, null);
}, "z can be set to null");
test(() => {
let translation = new CSSTranslation(zeroLength, zeroLength);
let translation = new CSSTranslation(CSS.px(0), CSS.px(0));
assert_throws(new TypeError(), () => {
translation.z = new CSSUnitValue(30, 'percent');
});
}, "Setting z throws for length containing percentage");
test(() => {
let expectedMatrix = (new DOMMatrixReadOnly()).translate(1, 2, 3);
let transformValue = new CSSTransformValue(
[new CSSTranslation(CSS.px(1), CSS.px(2), CSS.px(3))]);
assert_matrix_approx_equals(
transformValue.toMatrix(), expectedMatrix, EPSILON);
}, "toMatrix when used in a CSSTransformValue produces correct matrix");
test(() => {
let expectedMatrix = new DOMMatrixReadOnly();
let transformValue = new CSSTransformValue(
[new CSSTranslation(CSS.em(1), CSS.px(2), CSS.px(3))]);
assert_matrix_approx_equals(
transformValue.toMatrix(), expectedMatrix, EPSILON);
}, "toMatrix is the identity (instead of crashing) when relative lengths " +
"are used");
</script>
......@@ -7,12 +7,6 @@
<script>
let zeroAngle = new CSSUnitValue(0, 'deg');
function angleValue(value, unit) {
return new CSSUnitValue(value, unit);
}
function cssTransformWithRotate(angleValue) {
return new CSSTransformValue([
new CSSRotation(angleValue)]);
......@@ -30,27 +24,32 @@ runInlineStylePropertyMapTests( {
],
validObjects: [
// Translations
// TODO(meade)
new CSSTransformValue([new CSSTranslation(CSS.px(1), CSS.px(2))]),
new CSSTransformValue(
[new CSSTranslation(CSS.px(1), CSS.px(2), CSS.px(3))]),
new CSSTransformValue([new CSSTranslation(CSS.px(-10), CSS.px(-20))]),
new CSSTransformValue(
[new CSSTranslation(CSS.px(-10), CSS.px(-20), CSS.px(-30))]),
// Scales
// TODO(meade)
// Skews
new CSSTransformValue([new CSSSkew(angleValue(30, 'deg'), zeroAngle)]),
new CSSTransformValue([new CSSSkew(angleValue(10, 'rad'), zeroAngle)]),
new CSSTransformValue([new CSSSkew(angleValue(2, 'grad'), zeroAngle)]),
new CSSTransformValue([new CSSSkew(angleValue(0.2, 'turn'), zeroAngle)]),
new CSSTransformValue([new CSSSkew(zeroAngle, angleValue(30, 'deg'))]),
new CSSTransformValue([new CSSSkew(zeroAngle, angleValue(10, 'rad'))]),
new CSSTransformValue([new CSSSkew(zeroAngle, angleValue(2, 'grad'))]),
new CSSTransformValue([new CSSSkew(zeroAngle, angleValue(0.2, 'turn'))]),
new CSSTransformValue([new CSSSkew(CSS.deg(30), CSS.deg(0))]),
new CSSTransformValue([new CSSSkew(CSS.rad(10), CSS.deg(0))]),
new CSSTransformValue([new CSSSkew(CSS.grad(2), CSS.deg(0))]),
new CSSTransformValue([new CSSSkew(CSS.turn(0.2), CSS.deg(0))]),
new CSSTransformValue([new CSSSkew(CSS.deg(0), CSS.deg(30))]),
new CSSTransformValue([new CSSSkew(CSS.deg(0), CSS.rad(10))]),
new CSSTransformValue([new CSSSkew(CSS.deg(0), CSS.grad(2))]),
new CSSTransformValue([new CSSSkew(CSS.deg(0), CSS.turn(0.2))]),
// Rotations
cssTransformWithRotate(angleValue(30, 'deg')),
cssTransformWithRotate(angleValue(10, 'rad')),
cssTransformWithRotate(angleValue(2, 'grad')),
cssTransformWithRotate(angleValue(0.2, 'turn')),
cssTransformWithRotate3D(1, 2, 3, angleValue(30, 'deg')),
cssTransformWithRotate3D(1, 2, 3, angleValue(10, 'rad')),
cssTransformWithRotate3D(1, 2, 3, angleValue(2, 'grad')),
cssTransformWithRotate3D(1, 2, 3, angleValue(0.2, 'turn')),
cssTransformWithRotate(CSS.deg(30)),
cssTransformWithRotate(CSS.rad(10)),
cssTransformWithRotate(CSS.grad(2)),
cssTransformWithRotate(CSS.turn(0.2)),
cssTransformWithRotate3D(1, 2, 3, CSS.deg(30)),
cssTransformWithRotate3D(1, 2, 3, CSS.rad(10)),
cssTransformWithRotate3D(1, 2, 3, CSS.grad(2)),
cssTransformWithRotate3D(1, 2, 3, CSS.turn(0.2)),
// Perspectives
new CSSTransformValue([new CSSPerspective(CSS.px(10))]),
new CSSTransformValue([new CSSPerspective(CSS.em(5))]),
......@@ -58,53 +57,54 @@ runInlineStylePropertyMapTests( {
// Values with these strings aren't used in Typed OM, but can also be
// represented by the specified values.
validStringMappings: {
// Translations
'translate(10px)':
new CSSTransformValue([new CSSTranslation(CSS.px(10), CSS.px(0))]),
'translateX(10em)':
new CSSTransformValue([new CSSTranslation(CSS.em(10), CSS.px(0))]),
'translateY(20pc)':
new CSSTransformValue([new CSSTranslation(CSS.px(0), CSS.pc(20))]),
'translateZ(30in)':
new CSSTransformValue(
[new CSSTranslation(CSS.px(0), CSS.px(0), CSS.in(30))]),
// Skews
'skew(45deg)':
new CSSTransformValue([new CSSSkew(angleValue(45, 'deg'), zeroAngle)]),
'skew(1rad)':
new CSSTransformValue([new CSSSkew(angleValue(1, 'rad'), zeroAngle)]),
new CSSTransformValue([new CSSSkew(CSS.deg(45), CSS.deg(0))]),
'skew(1rad)': new CSSTransformValue([new CSSSkew(CSS.rad(1), CSS.deg(0))]),
'skew(6.2grad)':
new CSSTransformValue([new CSSSkew(angleValue(6.2, 'grad'), zeroAngle)]),
new CSSTransformValue([new CSSSkew(CSS.grad(6.2), CSS.deg(0))]),
'skew(0.31turn)':
new CSSTransformValue([new CSSSkew(angleValue(0.31, 'turn'), zeroAngle)]),
new CSSTransformValue([new CSSSkew(CSS.turn(0.31), CSS.deg(0))]),
'skewX(45deg)':
new CSSTransformValue([new CSSSkew(angleValue(45, 'deg'), zeroAngle)]),
'skewX(1rad)':
new CSSTransformValue([new CSSSkew(angleValue(1, 'rad'), zeroAngle)]),
new CSSTransformValue([new CSSSkew(CSS.deg(45), CSS.deg(0))]),
'skewX(1rad)': new CSSTransformValue([new CSSSkew(CSS.rad(1), CSS.deg(0))]),
'skewX(6.2grad)':
new CSSTransformValue([new CSSSkew(angleValue(6.2, 'grad'), zeroAngle)]),
new CSSTransformValue([new CSSSkew(CSS.grad(6.2), CSS.deg(0))]),
'skewX(0.31turn)':
new CSSTransformValue([new CSSSkew(angleValue(0.31, 'turn'), zeroAngle)]),
new CSSTransformValue([new CSSSkew(CSS.turn(0.31), CSS.deg(0))]),
'skewY(45deg)':
new CSSTransformValue([new CSSSkew(zeroAngle, angleValue(45, 'deg'))]),
'skewY(1rad)':
new CSSTransformValue([new CSSSkew(zeroAngle, angleValue(1, 'rad'))]),
new CSSTransformValue([new CSSSkew(CSS.deg(0), CSS.deg(45))]),
'skewY(1rad)': new CSSTransformValue([new CSSSkew(CSS.deg(0), CSS.rad(1))]),
'skewY(6.2grad)':
new CSSTransformValue([new CSSSkew(zeroAngle, angleValue(6.2, 'grad'))]),
new CSSTransformValue([new CSSSkew(CSS.deg(0), CSS.grad(6.2))]),
'skewY(0.31turn)':
new CSSTransformValue([new CSSSkew(zeroAngle, angleValue(0.31, 'turn'))]),
new CSSTransformValue([new CSSSkew(CSS.deg(0), CSS.turn(0.31))]),
// Rotations
'rotateX(45deg)': cssTransformWithRotate3D(1, 0, 0, angleValue(45, 'deg')),
'rotateX(1rad)': cssTransformWithRotate3D(1, 0, 0, angleValue(1, 'rad')),
'rotateX(6.2grad)':
cssTransformWithRotate3D(1, 0, 0, angleValue(6.2, 'grad')),
'rotateX(0.31turn)':
cssTransformWithRotate3D(1, 0, 0, angleValue(0.31, 'turn')),
'rotateY(45deg)': cssTransformWithRotate3D(0, 1, 0, angleValue(45, 'deg')),
'rotateY(1rad)': cssTransformWithRotate3D(0, 1, 0, angleValue(1, 'rad')),
'rotateY(6.2grad)':
cssTransformWithRotate3D(0, 1, 0, angleValue(6.2, 'grad')),
'rotateY(0.31turn)':
cssTransformWithRotate3D(0, 1, 0, angleValue(0.31, 'turn')),
'rotateZ(45deg)': cssTransformWithRotate3D(0, 0, 1, angleValue(45, 'deg')),
'rotateZ(1rad)': cssTransformWithRotate3D(0, 0, 1, angleValue(1, 'rad')),
'rotateZ(6.2grad)':
cssTransformWithRotate3D(0, 0, 1, angleValue(6.2, 'grad')),
'rotateZ(0.31turn)':
cssTransformWithRotate3D(0, 0, 1, angleValue(0.31, 'turn')),
'rotateX(45deg)': cssTransformWithRotate3D(1, 0, 0, CSS.deg(45)),
'rotateX(1rad)': cssTransformWithRotate3D(1, 0, 0, CSS.rad(1)),
'rotateX(6.2grad)': cssTransformWithRotate3D(1, 0, 0, CSS.grad(6.2)),
'rotateX(0.31turn)': cssTransformWithRotate3D(1, 0, 0, CSS.turn(0.31)),
'rotateY(45deg)': cssTransformWithRotate3D(0, 1, 0, CSS.deg(45)),
'rotateY(1rad)': cssTransformWithRotate3D(0, 1, 0, CSS.rad(1)),
'rotateY(6.2grad)': cssTransformWithRotate3D(0, 1, 0, CSS.grad(6.2)),
'rotateY(0.31turn)': cssTransformWithRotate3D(0, 1, 0, CSS.turn(0.31)),
'rotateZ(45deg)': cssTransformWithRotate3D(0, 0, 1, CSS.deg(45)),
'rotateZ(1rad)': cssTransformWithRotate3D(0, 0, 1, CSS.rad(1)),
'rotateZ(6.2grad)': cssTransformWithRotate3D(0, 0, 1, CSS.grad(6.2)),
'rotateZ(0.31turn)': cssTransformWithRotate3D(0, 0, 1, CSS.turn(0.31)),
},
supportsMultiple: false,
invalidObjects: [new CSSUnitValue(4, 'px')]
invalidObjects: [CSS.px(4)]
});
let crashTestStrings = {
......
......@@ -8,16 +8,98 @@
#include "core/css/CSSPrimitiveValue.h"
#include "core/css/cssom/CSSNumericValue.h"
#include "core/css/cssom/CSSStyleValue.h"
#include "core/geometry/DOMMatrix.h"
namespace blink {
namespace {
bool IsLengthOrPercent(const CSSNumericValue* value) {
return (value->GetType() == CSSStyleValue::StyleValueType::kLengthType ||
value->GetType() == CSSStyleValue::StyleValueType::kPercentType);
}
bool IsLengthValue(const CSSValue& value) {
return value.IsPrimitiveValue() && ToCSSPrimitiveValue(value).IsLength();
}
CSSTranslation* FromCSSTranslate(const CSSFunctionValue& value) {
DCHECK_GT(value.length(), 0UL);
DCHECK(IsLengthValue(value.Item(0)));
CSSNumericValue* x =
CSSNumericValue::FromCSSValue(ToCSSPrimitiveValue(value.Item(0)));
if (!x)
return nullptr;
if (value.length() == 1) {
return CSSTranslation::Create(
x, CSSUnitValue::Create(0, CSSPrimitiveValue::UnitType::kPixels));
}
DCHECK_EQ(value.length(), 2UL);
DCHECK(IsLengthValue(value.Item(1)));
CSSNumericValue* y =
CSSNumericValue::FromCSSValue(ToCSSPrimitiveValue(value.Item(1)));
if (!y)
return nullptr;
return CSSTranslation::Create(x, y);
}
CSSTranslation* FromCSSTranslateXYZ(const CSSFunctionValue& value) {
DCHECK_EQ(value.length(), 1UL);
DCHECK(IsLengthValue(value.Item(0)));
CSSNumericValue* length =
CSSNumericValue::FromCSSValue(ToCSSPrimitiveValue(value.Item(0)));
if (!length)
return nullptr;
switch (value.FunctionType()) {
case CSSValueTranslateX:
return CSSTranslation::Create(
length,
CSSUnitValue::Create(0, CSSPrimitiveValue::UnitType::kPixels));
case CSSValueTranslateY:
return CSSTranslation::Create(
CSSUnitValue::Create(0, CSSPrimitiveValue::UnitType::kPixels),
length);
case CSSValueTranslateZ:
return CSSTranslation::Create(
CSSUnitValue::Create(0, CSSPrimitiveValue::UnitType::kPixels),
CSSUnitValue::Create(0, CSSPrimitiveValue::UnitType::kPixels),
length);
default:
NOTREACHED();
return nullptr;
}
}
CSSTranslation* FromCSSTranslate3D(const CSSFunctionValue& value) {
DCHECK_EQ(value.length(), 3UL);
DCHECK(IsLengthValue(value.Item(0)));
DCHECK(IsLengthValue(value.Item(1)));
DCHECK(IsLengthValue(value.Item(2)));
CSSNumericValue* x =
CSSNumericValue::FromCSSValue(ToCSSPrimitiveValue(value.Item(0)));
CSSNumericValue* y =
CSSNumericValue::FromCSSValue(ToCSSPrimitiveValue(value.Item(1)));
CSSNumericValue* z =
CSSNumericValue::FromCSSValue(ToCSSPrimitiveValue(value.Item(2)));
if (!x || !y || !z)
return nullptr;
return CSSTranslation::Create(x, y, z);
}
} // namespace
CSSTranslation* CSSTranslation::Create(CSSNumericValue* x,
CSSNumericValue* y,
ExceptionState& exception_state) {
if ((x->GetType() != CSSStyleValue::StyleValueType::kLengthType &&
x->GetType() != CSSStyleValue::StyleValueType::kPercentType) ||
(y->GetType() != CSSStyleValue::StyleValueType::kLengthType &&
y->GetType() != CSSStyleValue::StyleValueType::kPercentType)) {
if (!IsLengthOrPercent(x) || !IsLengthOrPercent(y)) {
exception_state.ThrowTypeError(
"Must pass length or percentage to X and Y of CSSTranslation");
return nullptr;
......@@ -31,10 +113,7 @@ CSSTranslation* CSSTranslation::Create(CSSNumericValue* x,
CSSNumericValue* y,
CSSNumericValue* z,
ExceptionState& exception_state) {
if ((x->GetType() != CSSStyleValue::StyleValueType::kLengthType &&
x->GetType() != CSSStyleValue::StyleValueType::kPercentType) ||
(y->GetType() != CSSStyleValue::StyleValueType::kLengthType &&
y->GetType() != CSSStyleValue::StyleValueType::kPercentType)) {
if (!IsLengthOrPercent(x) || !IsLengthOrPercent(y)) {
exception_state.ThrowTypeError(
"Must pass length or percentage to X and Y of CSSTranslation");
return nullptr;
......@@ -51,6 +130,40 @@ CSSTranslation* CSSTranslation::Create(CSSNumericValue* x,
return new CSSTranslation(x, y, z, false /* is2D */);
}
CSSTranslation* CSSTranslation::Create(CSSNumericValue* x, CSSNumericValue* y) {
DCHECK(IsLengthOrPercent(x));
DCHECK(IsLengthOrPercent(y));
return new CSSTranslation(
x, y, CSSUnitValue::Create(0, CSSPrimitiveValue::UnitType::kPixels),
true /* is2D */);
}
CSSTranslation* CSSTranslation::Create(CSSNumericValue* x,
CSSNumericValue* y,
CSSNumericValue* z) {
DCHECK(IsLengthOrPercent(x));
DCHECK(IsLengthOrPercent(y));
DCHECK_EQ(z->GetType(), CSSStyleValue::StyleValueType::kLengthType);
DCHECK(!z->ContainsPercent());
return new CSSTranslation(x, y, z, false /* is2D */);
}
CSSTranslation* CSSTranslation::FromCSSValue(const CSSFunctionValue& value) {
switch (value.FunctionType()) {
case CSSValueTranslateX:
case CSSValueTranslateY:
case CSSValueTranslateZ:
return FromCSSTranslateXYZ(value);
case CSSValueTranslate:
return FromCSSTranslate(value);
case CSSValueTranslate3d:
return FromCSSTranslate3D(value);
default:
NOTREACHED();
return nullptr;
}
}
void CSSTranslation::setX(CSSNumericValue* x, ExceptionState& exception_state) {
if (x->GetType() != CSSStyleValue::StyleValueType::kLengthType &&
x->GetType() != CSSStyleValue::StyleValueType::kPercentType) {
......@@ -72,11 +185,11 @@ void CSSTranslation::setY(CSSNumericValue* y, ExceptionState& exception_state) {
}
void CSSTranslation::setZ(CSSNumericValue* z, ExceptionState& exception_state) {
if (z && z->GetType() != CSSStyleValue::StyleValueType::kLengthType) {
if (z->GetType() != CSSStyleValue::StyleValueType::kLengthType) {
exception_state.ThrowTypeError("Must pass length to Z of CSSTranslation");
return;
}
if (z && z->ContainsPercent()) {
if (z->ContainsPercent()) {
exception_state.ThrowTypeError(
"CSSTranslation does not support z CSSNumericValue with percent units");
return;
......@@ -84,6 +197,20 @@ void CSSTranslation::setZ(CSSNumericValue* z, ExceptionState& exception_state) {
z_ = z;
}
DOMMatrix* CSSTranslation::AsMatrix() const {
CSSUnitValue* x = x_->to(CSSPrimitiveValue::UnitType::kPixels);
CSSUnitValue* y = y_->to(CSSPrimitiveValue::UnitType::kPixels);
CSSUnitValue* z = z_->to(CSSPrimitiveValue::UnitType::kPixels);
// TODO(meade): What should happen when the translation contains relative
// lengths here?
// https://github.com/w3c/css-houdini-drafts/issues/421
if (!x || !y || !z)
return nullptr;
DOMMatrix* matrix = DOMMatrix::Create();
return matrix->translate(x->value(), y->value(), z->value());
}
CSSFunctionValue* CSSTranslation::ToCSSValue() const {
CSSFunctionValue* result = CSSFunctionValue::Create(
is2D() ? CSSValueTranslate : CSSValueTranslate3d);
......
......@@ -34,9 +34,11 @@ class CORE_EXPORT CSSTranslation final : public CSSTransformComponent {
ExceptionState&);
// Blink-internal ways of creating CSSTranslations.
static CSSTranslation* FromCSSValue(const CSSFunctionValue& value) {
return nullptr;
}
static CSSTranslation* Create(CSSNumericValue* x, CSSNumericValue* y);
static CSSTranslation* Create(CSSNumericValue* x,
CSSNumericValue* y,
CSSNumericValue* z);
static CSSTranslation* FromCSSValue(const CSSFunctionValue&);
// Getters and setters for attributes defined in the IDL.
CSSNumericValue* x() const { return x_; }
......@@ -48,8 +50,7 @@ class CORE_EXPORT CSSTranslation final : public CSSTransformComponent {
// Internal methods - from CSSTransformComponent.
TransformComponentType GetType() const final { return kTranslationType; }
// TODO: Implement AsMatrix for CSSTranslation.
DOMMatrix* AsMatrix() const final { return nullptr; }
DOMMatrix* AsMatrix() const final;
CSSFunctionValue* ToCSSValue() const final;
DEFINE_INLINE_VIRTUAL_TRACE() {
......
......@@ -14,5 +14,5 @@
] interface CSSTranslation : CSSTransformComponent {
[RaisesException=Setter] attribute CSSNumericValue x;
[RaisesException=Setter] attribute CSSNumericValue y;
[RaisesException=Setter] attribute CSSNumericValue? z;
[RaisesException=Setter] attribute CSSNumericValue z;
};
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment