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> <!DOCTYPE html>
<script src="../resources/testharness.js"></script> <script src="../resources/testharness.js"></script>
<script src="../resources/testharnessreport.js"></script> <script src="../resources/testharnessreport.js"></script>
<script src="resources/comparisons.js"></script>
<script> <script>
let EPSILON = 1e-6;
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");
var testParams = [ var testParams = [
// 2D translations // 2D translations
{ {
input: new CSSTranslation(zeroLength, zeroLength), input: new CSSTranslation(CSS.px(0), CSS.px(0)),
x: zeroLength, y: zeroLength, x: CSS.px(0), y: CSS.px(0),
is2D: true, is2D: true,
cssText: "translate(0px, 0px)" cssText: "translate(0px, 0px)"
}, },
{ {
input: new CSSTranslation(decimalLength, negativeLength), input: new CSSTranslation(CSS.px(1.1), CSS.em(-2.2)),
x: decimalLength, y: negativeLength, x: CSS.px(1.1), y: CSS.em(-2.2),
is2D: true, is2D: true,
cssText: "translate(1.1px, -2.2em)" cssText: "translate(1.1px, -2.2em)"
}, },
{ {
input: new CSSTranslation(tenPercent, zeroLength), input: new CSSTranslation(CSS.percent(10), CSS.px(0)),
x: tenPercent, y: zeroLength, x: CSS.percent(10), y: CSS.px(0),
is2D: true, is2D: true,
cssText: "translate(10%, 0px)" cssText: "translate(10%, 0px)"
}, },
// 3D translations // 3D translations
{ {
input: new CSSTranslation(zeroLength, zeroLength, zeroLength), input: new CSSTranslation(CSS.px(0), CSS.px(0), CSS.px(0)),
x: zeroLength, y: zeroLength, z: zeroLength, x: CSS.px(0), y: CSS.px(0), z: CSS.px(0),
is2D: false, is2D: false,
cssText: "translate3d(0px, 0px, 0px)" cssText: "translate3d(0px, 0px, 0px)"
}, },
{ {
input: new CSSTranslation(zeroLength, decimalLength, negativeLength), input: new CSSTranslation(CSS.px(0), CSS.px(1.1), CSS.em(-2.2)),
x: zeroLength, y: decimalLength, z: negativeLength, x: CSS.px(0), y: CSS.px(1.1), z: CSS.em(-2.2),
is2D: false, is2D: false,
cssText: "translate3d(0px, 1.1px, -2.2em)" cssText: "translate3d(0px, 1.1px, -2.2em)"
}, },
{ {
input: new CSSTranslation(tenPercent, decimalLength, zeroLength), input: new CSSTranslation(CSS.percent(10), CSS.px(1.1), CSS.px(0)),
x: tenPercent, y: decimalLength, z: zeroLength, x: CSS.percent(10), y: CSS.px(1.1), z: CSS.px(0),
is2D: false, is2D: false,
cssText: "translate3d(10%, 1.1px, 0px)" cssText: "translate3d(10%, 1.1px, 0px)"
}, },
...@@ -52,12 +49,15 @@ var testParams = [ ...@@ -52,12 +49,15 @@ var testParams = [
for (let params of testParams) { for (let params of testParams) {
test(() => { test(() => {
assert_equals(params.input.x, params.x); assert_equals(params.input.x.value, params.x.value);
assert_equals(params.input.y, params.y); 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) { if (params.is2D) {
assert_equals(params.input.z.value, 0); assert_equals(params.input.z.value, 0);
} else { } 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); }, "x, y, and z values are correct for " + params.cssText);
...@@ -83,7 +83,7 @@ test(() => { ...@@ -83,7 +83,7 @@ test(() => {
let translation3d = new CSSTranslation( let translation3d = new CSSTranslation(
new CSSUnitValue(30, 'percent'), new CSSUnitValue(30, 'percent'),
new CSSUnitValue(40, 'percent'), new CSSUnitValue(40, 'percent'),
zeroLength); CSS.px(0));
assert_equals(translation3d.x.value, 30); assert_equals(translation3d.x.value, 30);
assert_equals(translation3d.x.unit, 'percent'); assert_equals(translation3d.x.unit, 'percent');
assert_equals(translation3d.y.value, 40); assert_equals(translation3d.y.value, 40);
...@@ -93,34 +93,34 @@ test(() => { ...@@ -93,34 +93,34 @@ test(() => {
test(() => { test(() => {
assert_throws(new TypeError(), () => { assert_throws(new TypeError(), () => {
new CSSTranslation(new CSSUnitValue(10, 'deg'), zeroLength); new CSSTranslation(new CSSUnitValue(10, 'deg'), CSS.px(0));
}); });
assert_throws(new TypeError(), () => { assert_throws(new TypeError(), () => {
new CSSTranslation(zeroLength, new CSSUnitValue(10, 'deg')); new CSSTranslation(CSS.px(0), new CSSUnitValue(10, 'deg'));
}); });
assert_throws(new TypeError(), () => { 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(), () => { 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(), () => { 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"); }, "Constructor throws when invalid numeric values are given to each argument");
test(() => { test(() => {
assert_throws(new TypeError(), () => { assert_throws(new TypeError(), () => {
new CSSTranslation(zeroLength, zeroLength, tenPercent); new CSSTranslation(CSS.px(0), CSS.px(0), CSS.percent(10));
}); });
assert_throws(new TypeError(), () => { 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."); }, "Constructor throws when z argument contains percent.");
test(() => { test(() => {
assert_throws(new TypeError(), () => { new CSSTranslation(); }); 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."); }, "Invalid number of arguments to constructor throws an exception.");
for (let attribute of ["x", "y"]) { for (let attribute of ["x", "y"]) {
...@@ -160,20 +160,27 @@ for (let attribute of ["x", "y", "z"]) { ...@@ -160,20 +160,27 @@ for (let attribute of ["x", "y", "z"]) {
} }
test(() => { test(() => {
let validLength = new CSSUnitValue(5, 'px'); let translation = new CSSTranslation(CSS.px(0), CSS.px(0));
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);
assert_throws(new TypeError(), () => { assert_throws(new TypeError(), () => {
translation.z = new CSSUnitValue(30, 'percent'); translation.z = new CSSUnitValue(30, 'percent');
}); });
}, "Setting z throws for length containing percentage"); }, "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> </script>
...@@ -7,12 +7,6 @@ ...@@ -7,12 +7,6 @@
<script> <script>
let zeroAngle = new CSSUnitValue(0, 'deg');
function angleValue(value, unit) {
return new CSSUnitValue(value, unit);
}
function cssTransformWithRotate(angleValue) { function cssTransformWithRotate(angleValue) {
return new CSSTransformValue([ return new CSSTransformValue([
new CSSRotation(angleValue)]); new CSSRotation(angleValue)]);
...@@ -30,27 +24,32 @@ runInlineStylePropertyMapTests( { ...@@ -30,27 +24,32 @@ runInlineStylePropertyMapTests( {
], ],
validObjects: [ validObjects: [
// Translations // 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 // Scales
// TODO(meade) // TODO(meade)
// Skews // Skews
new CSSTransformValue([new CSSSkew(angleValue(30, 'deg'), zeroAngle)]), new CSSTransformValue([new CSSSkew(CSS.deg(30), CSS.deg(0))]),
new CSSTransformValue([new CSSSkew(angleValue(10, 'rad'), zeroAngle)]), new CSSTransformValue([new CSSSkew(CSS.rad(10), CSS.deg(0))]),
new CSSTransformValue([new CSSSkew(angleValue(2, 'grad'), zeroAngle)]), new CSSTransformValue([new CSSSkew(CSS.grad(2), CSS.deg(0))]),
new CSSTransformValue([new CSSSkew(angleValue(0.2, 'turn'), zeroAngle)]), new CSSTransformValue([new CSSSkew(CSS.turn(0.2), CSS.deg(0))]),
new CSSTransformValue([new CSSSkew(zeroAngle, angleValue(30, 'deg'))]), new CSSTransformValue([new CSSSkew(CSS.deg(0), CSS.deg(30))]),
new CSSTransformValue([new CSSSkew(zeroAngle, angleValue(10, 'rad'))]), new CSSTransformValue([new CSSSkew(CSS.deg(0), CSS.rad(10))]),
new CSSTransformValue([new CSSSkew(zeroAngle, angleValue(2, 'grad'))]), new CSSTransformValue([new CSSSkew(CSS.deg(0), CSS.grad(2))]),
new CSSTransformValue([new CSSSkew(zeroAngle, angleValue(0.2, 'turn'))]), new CSSTransformValue([new CSSSkew(CSS.deg(0), CSS.turn(0.2))]),
// Rotations // Rotations
cssTransformWithRotate(angleValue(30, 'deg')), cssTransformWithRotate(CSS.deg(30)),
cssTransformWithRotate(angleValue(10, 'rad')), cssTransformWithRotate(CSS.rad(10)),
cssTransformWithRotate(angleValue(2, 'grad')), cssTransformWithRotate(CSS.grad(2)),
cssTransformWithRotate(angleValue(0.2, 'turn')), cssTransformWithRotate(CSS.turn(0.2)),
cssTransformWithRotate3D(1, 2, 3, angleValue(30, 'deg')), cssTransformWithRotate3D(1, 2, 3, CSS.deg(30)),
cssTransformWithRotate3D(1, 2, 3, angleValue(10, 'rad')), cssTransformWithRotate3D(1, 2, 3, CSS.rad(10)),
cssTransformWithRotate3D(1, 2, 3, angleValue(2, 'grad')), cssTransformWithRotate3D(1, 2, 3, CSS.grad(2)),
cssTransformWithRotate3D(1, 2, 3, angleValue(0.2, 'turn')), cssTransformWithRotate3D(1, 2, 3, CSS.turn(0.2)),
// Perspectives // Perspectives
new CSSTransformValue([new CSSPerspective(CSS.px(10))]), new CSSTransformValue([new CSSPerspective(CSS.px(10))]),
new CSSTransformValue([new CSSPerspective(CSS.em(5))]), new CSSTransformValue([new CSSPerspective(CSS.em(5))]),
...@@ -58,53 +57,54 @@ runInlineStylePropertyMapTests( { ...@@ -58,53 +57,54 @@ runInlineStylePropertyMapTests( {
// Values with these strings aren't used in Typed OM, but can also be // Values with these strings aren't used in Typed OM, but can also be
// represented by the specified values. // represented by the specified values.
validStringMappings: { 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 // Skews
'skew(45deg)': 'skew(45deg)':
new CSSTransformValue([new CSSSkew(angleValue(45, 'deg'), zeroAngle)]), new CSSTransformValue([new CSSSkew(CSS.deg(45), CSS.deg(0))]),
'skew(1rad)': 'skew(1rad)': new CSSTransformValue([new CSSSkew(CSS.rad(1), CSS.deg(0))]),
new CSSTransformValue([new CSSSkew(angleValue(1, 'rad'), zeroAngle)]),
'skew(6.2grad)': '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)': '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)': 'skewX(45deg)':
new CSSTransformValue([new CSSSkew(angleValue(45, 'deg'), zeroAngle)]), new CSSTransformValue([new CSSSkew(CSS.deg(45), CSS.deg(0))]),
'skewX(1rad)': 'skewX(1rad)': new CSSTransformValue([new CSSSkew(CSS.rad(1), CSS.deg(0))]),
new CSSTransformValue([new CSSSkew(angleValue(1, 'rad'), zeroAngle)]),
'skewX(6.2grad)': '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)': '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)': 'skewY(45deg)':
new CSSTransformValue([new CSSSkew(zeroAngle, angleValue(45, 'deg'))]), new CSSTransformValue([new CSSSkew(CSS.deg(0), CSS.deg(45))]),
'skewY(1rad)': 'skewY(1rad)': new CSSTransformValue([new CSSSkew(CSS.deg(0), CSS.rad(1))]),
new CSSTransformValue([new CSSSkew(zeroAngle, angleValue(1, 'rad'))]),
'skewY(6.2grad)': '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)': 'skewY(0.31turn)':
new CSSTransformValue([new CSSSkew(zeroAngle, angleValue(0.31, 'turn'))]), new CSSTransformValue([new CSSSkew(CSS.deg(0), CSS.turn(0.31))]),
// Rotations // Rotations
'rotateX(45deg)': cssTransformWithRotate3D(1, 0, 0, angleValue(45, 'deg')), 'rotateX(45deg)': cssTransformWithRotate3D(1, 0, 0, CSS.deg(45)),
'rotateX(1rad)': cssTransformWithRotate3D(1, 0, 0, angleValue(1, 'rad')), 'rotateX(1rad)': cssTransformWithRotate3D(1, 0, 0, CSS.rad(1)),
'rotateX(6.2grad)': 'rotateX(6.2grad)': cssTransformWithRotate3D(1, 0, 0, CSS.grad(6.2)),
cssTransformWithRotate3D(1, 0, 0, angleValue(6.2, 'grad')), 'rotateX(0.31turn)': cssTransformWithRotate3D(1, 0, 0, CSS.turn(0.31)),
'rotateX(0.31turn)': 'rotateY(45deg)': cssTransformWithRotate3D(0, 1, 0, CSS.deg(45)),
cssTransformWithRotate3D(1, 0, 0, angleValue(0.31, 'turn')), 'rotateY(1rad)': cssTransformWithRotate3D(0, 1, 0, CSS.rad(1)),
'rotateY(45deg)': cssTransformWithRotate3D(0, 1, 0, angleValue(45, 'deg')), 'rotateY(6.2grad)': cssTransformWithRotate3D(0, 1, 0, CSS.grad(6.2)),
'rotateY(1rad)': cssTransformWithRotate3D(0, 1, 0, angleValue(1, 'rad')), 'rotateY(0.31turn)': cssTransformWithRotate3D(0, 1, 0, CSS.turn(0.31)),
'rotateY(6.2grad)': 'rotateZ(45deg)': cssTransformWithRotate3D(0, 0, 1, CSS.deg(45)),
cssTransformWithRotate3D(0, 1, 0, angleValue(6.2, 'grad')), 'rotateZ(1rad)': cssTransformWithRotate3D(0, 0, 1, CSS.rad(1)),
'rotateY(0.31turn)': 'rotateZ(6.2grad)': cssTransformWithRotate3D(0, 0, 1, CSS.grad(6.2)),
cssTransformWithRotate3D(0, 1, 0, angleValue(0.31, 'turn')), 'rotateZ(0.31turn)': cssTransformWithRotate3D(0, 0, 1, CSS.turn(0.31)),
'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')),
}, },
supportsMultiple: false, supportsMultiple: false,
invalidObjects: [new CSSUnitValue(4, 'px')] invalidObjects: [CSS.px(4)]
}); });
let crashTestStrings = { let crashTestStrings = {
......
...@@ -8,16 +8,98 @@ ...@@ -8,16 +8,98 @@
#include "core/css/CSSPrimitiveValue.h" #include "core/css/CSSPrimitiveValue.h"
#include "core/css/cssom/CSSNumericValue.h" #include "core/css/cssom/CSSNumericValue.h"
#include "core/css/cssom/CSSStyleValue.h" #include "core/css/cssom/CSSStyleValue.h"
#include "core/geometry/DOMMatrix.h"
namespace blink { 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, CSSTranslation* CSSTranslation::Create(CSSNumericValue* x,
CSSNumericValue* y, CSSNumericValue* y,
ExceptionState& exception_state) { ExceptionState& exception_state) {
if ((x->GetType() != CSSStyleValue::StyleValueType::kLengthType && if (!IsLengthOrPercent(x) || !IsLengthOrPercent(y)) {
x->GetType() != CSSStyleValue::StyleValueType::kPercentType) ||
(y->GetType() != CSSStyleValue::StyleValueType::kLengthType &&
y->GetType() != CSSStyleValue::StyleValueType::kPercentType)) {
exception_state.ThrowTypeError( exception_state.ThrowTypeError(
"Must pass length or percentage to X and Y of CSSTranslation"); "Must pass length or percentage to X and Y of CSSTranslation");
return nullptr; return nullptr;
...@@ -31,10 +113,7 @@ CSSTranslation* CSSTranslation::Create(CSSNumericValue* x, ...@@ -31,10 +113,7 @@ CSSTranslation* CSSTranslation::Create(CSSNumericValue* x,
CSSNumericValue* y, CSSNumericValue* y,
CSSNumericValue* z, CSSNumericValue* z,
ExceptionState& exception_state) { ExceptionState& exception_state) {
if ((x->GetType() != CSSStyleValue::StyleValueType::kLengthType && if (!IsLengthOrPercent(x) || !IsLengthOrPercent(y)) {
x->GetType() != CSSStyleValue::StyleValueType::kPercentType) ||
(y->GetType() != CSSStyleValue::StyleValueType::kLengthType &&
y->GetType() != CSSStyleValue::StyleValueType::kPercentType)) {
exception_state.ThrowTypeError( exception_state.ThrowTypeError(
"Must pass length or percentage to X and Y of CSSTranslation"); "Must pass length or percentage to X and Y of CSSTranslation");
return nullptr; return nullptr;
...@@ -51,6 +130,40 @@ CSSTranslation* CSSTranslation::Create(CSSNumericValue* x, ...@@ -51,6 +130,40 @@ CSSTranslation* CSSTranslation::Create(CSSNumericValue* x,
return new CSSTranslation(x, y, z, false /* is2D */); 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) { void CSSTranslation::setX(CSSNumericValue* x, ExceptionState& exception_state) {
if (x->GetType() != CSSStyleValue::StyleValueType::kLengthType && if (x->GetType() != CSSStyleValue::StyleValueType::kLengthType &&
x->GetType() != CSSStyleValue::StyleValueType::kPercentType) { x->GetType() != CSSStyleValue::StyleValueType::kPercentType) {
...@@ -72,11 +185,11 @@ void CSSTranslation::setY(CSSNumericValue* y, ExceptionState& exception_state) { ...@@ -72,11 +185,11 @@ void CSSTranslation::setY(CSSNumericValue* y, ExceptionState& exception_state) {
} }
void CSSTranslation::setZ(CSSNumericValue* z, 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"); exception_state.ThrowTypeError("Must pass length to Z of CSSTranslation");
return; return;
} }
if (z && z->ContainsPercent()) { if (z->ContainsPercent()) {
exception_state.ThrowTypeError( exception_state.ThrowTypeError(
"CSSTranslation does not support z CSSNumericValue with percent units"); "CSSTranslation does not support z CSSNumericValue with percent units");
return; return;
...@@ -84,6 +197,20 @@ void CSSTranslation::setZ(CSSNumericValue* z, ExceptionState& exception_state) { ...@@ -84,6 +197,20 @@ void CSSTranslation::setZ(CSSNumericValue* z, ExceptionState& exception_state) {
z_ = z; 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* CSSTranslation::ToCSSValue() const {
CSSFunctionValue* result = CSSFunctionValue::Create( CSSFunctionValue* result = CSSFunctionValue::Create(
is2D() ? CSSValueTranslate : CSSValueTranslate3d); is2D() ? CSSValueTranslate : CSSValueTranslate3d);
......
...@@ -34,9 +34,11 @@ class CORE_EXPORT CSSTranslation final : public CSSTransformComponent { ...@@ -34,9 +34,11 @@ class CORE_EXPORT CSSTranslation final : public CSSTransformComponent {
ExceptionState&); ExceptionState&);
// Blink-internal ways of creating CSSTranslations. // Blink-internal ways of creating CSSTranslations.
static CSSTranslation* FromCSSValue(const CSSFunctionValue& value) { static CSSTranslation* Create(CSSNumericValue* x, CSSNumericValue* y);
return nullptr; static CSSTranslation* Create(CSSNumericValue* x,
} CSSNumericValue* y,
CSSNumericValue* z);
static CSSTranslation* FromCSSValue(const CSSFunctionValue&);
// Getters and setters for attributes defined in the IDL. // Getters and setters for attributes defined in the IDL.
CSSNumericValue* x() const { return x_; } CSSNumericValue* x() const { return x_; }
...@@ -48,8 +50,7 @@ class CORE_EXPORT CSSTranslation final : public CSSTransformComponent { ...@@ -48,8 +50,7 @@ class CORE_EXPORT CSSTranslation final : public CSSTransformComponent {
// Internal methods - from CSSTransformComponent. // Internal methods - from CSSTransformComponent.
TransformComponentType GetType() const final { return kTranslationType; } TransformComponentType GetType() const final { return kTranslationType; }
// TODO: Implement AsMatrix for CSSTranslation. DOMMatrix* AsMatrix() const final;
DOMMatrix* AsMatrix() const final { return nullptr; }
CSSFunctionValue* ToCSSValue() const final; CSSFunctionValue* ToCSSValue() const final;
DEFINE_INLINE_VIRTUAL_TRACE() { DEFINE_INLINE_VIRTUAL_TRACE() {
......
...@@ -14,5 +14,5 @@ ...@@ -14,5 +14,5 @@
] interface CSSTranslation : CSSTransformComponent { ] interface CSSTranslation : CSSTransformComponent {
[RaisesException=Setter] attribute CSSNumericValue x; [RaisesException=Setter] attribute CSSNumericValue x;
[RaisesException=Setter] attribute CSSNumericValue y; [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