OLD | NEW |
1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "core/css/cssom/CSSTranslation.h" | 5 #include "core/css/cssom/CSSTranslation.h" |
6 | 6 |
7 #include "bindings/core/v8/ExceptionState.h" | 7 #include "bindings/core/v8/ExceptionState.h" |
8 #include "core/css/CSSPrimitiveValue.h" | 8 #include "core/css/CSSPrimitiveValue.h" |
9 #include "core/css/cssom/CSSNumericValue.h" | 9 #include "core/css/cssom/CSSNumericValue.h" |
10 #include "core/css/cssom/CSSStyleValue.h" | 10 #include "core/css/cssom/CSSStyleValue.h" |
| 11 #include "core/geometry/DOMMatrix.h" |
11 | 12 |
12 namespace blink { | 13 namespace blink { |
13 | 14 |
| 15 namespace { |
| 16 |
| 17 bool IsLengthOrPercent(const CSSNumericValue* value) { |
| 18 return (value->GetType() == CSSStyleValue::StyleValueType::kLengthType || |
| 19 value->GetType() == CSSStyleValue::StyleValueType::kPercentType); |
| 20 } |
| 21 |
| 22 bool IsLengthValue(const CSSValue& value) { |
| 23 return value.IsPrimitiveValue() && ToCSSPrimitiveValue(value).IsLength(); |
| 24 } |
| 25 |
| 26 CSSTranslation* FromCSSTranslate(const CSSFunctionValue& value) { |
| 27 DCHECK_GT(value.length(), 0UL); |
| 28 DCHECK(IsLengthValue(value.Item(0))); |
| 29 |
| 30 CSSNumericValue* x = |
| 31 CSSNumericValue::FromCSSValue(ToCSSPrimitiveValue(value.Item(0))); |
| 32 if (!x) |
| 33 return nullptr; |
| 34 |
| 35 if (value.length() == 1) { |
| 36 return CSSTranslation::Create( |
| 37 x, CSSUnitValue::Create(0, CSSPrimitiveValue::UnitType::kPixels)); |
| 38 } |
| 39 |
| 40 DCHECK_EQ(value.length(), 2UL); |
| 41 DCHECK(IsLengthValue(value.Item(1))); |
| 42 |
| 43 CSSNumericValue* y = |
| 44 CSSNumericValue::FromCSSValue(ToCSSPrimitiveValue(value.Item(1))); |
| 45 if (!y) |
| 46 return nullptr; |
| 47 return CSSTranslation::Create(x, y); |
| 48 } |
| 49 |
| 50 CSSTranslation* FromCSSTranslateXYZ(const CSSFunctionValue& value) { |
| 51 DCHECK_EQ(value.length(), 1UL); |
| 52 DCHECK(IsLengthValue(value.Item(0))); |
| 53 |
| 54 CSSNumericValue* length = |
| 55 CSSNumericValue::FromCSSValue(ToCSSPrimitiveValue(value.Item(0))); |
| 56 if (!length) |
| 57 return nullptr; |
| 58 |
| 59 switch (value.FunctionType()) { |
| 60 case CSSValueTranslateX: |
| 61 return CSSTranslation::Create( |
| 62 length, |
| 63 CSSUnitValue::Create(0, CSSPrimitiveValue::UnitType::kPixels)); |
| 64 case CSSValueTranslateY: |
| 65 return CSSTranslation::Create( |
| 66 CSSUnitValue::Create(0, CSSPrimitiveValue::UnitType::kPixels), |
| 67 length); |
| 68 case CSSValueTranslateZ: |
| 69 return CSSTranslation::Create( |
| 70 CSSUnitValue::Create(0, CSSPrimitiveValue::UnitType::kPixels), |
| 71 CSSUnitValue::Create(0, CSSPrimitiveValue::UnitType::kPixels), |
| 72 length); |
| 73 default: |
| 74 NOTREACHED(); |
| 75 return nullptr; |
| 76 } |
| 77 } |
| 78 |
| 79 CSSTranslation* FromCSSTranslate3D(const CSSFunctionValue& value) { |
| 80 DCHECK_EQ(value.length(), 3UL); |
| 81 DCHECK(IsLengthValue(value.Item(0))); |
| 82 DCHECK(IsLengthValue(value.Item(1))); |
| 83 DCHECK(IsLengthValue(value.Item(2))); |
| 84 |
| 85 CSSNumericValue* x = |
| 86 CSSNumericValue::FromCSSValue(ToCSSPrimitiveValue(value.Item(0))); |
| 87 CSSNumericValue* y = |
| 88 CSSNumericValue::FromCSSValue(ToCSSPrimitiveValue(value.Item(1))); |
| 89 CSSNumericValue* z = |
| 90 CSSNumericValue::FromCSSValue(ToCSSPrimitiveValue(value.Item(2))); |
| 91 if (!x || !y || !z) |
| 92 return nullptr; |
| 93 |
| 94 return CSSTranslation::Create(x, y, z); |
| 95 } |
| 96 |
| 97 } // namespace |
| 98 |
14 CSSTranslation* CSSTranslation::Create(CSSNumericValue* x, | 99 CSSTranslation* CSSTranslation::Create(CSSNumericValue* x, |
15 CSSNumericValue* y, | 100 CSSNumericValue* y, |
16 ExceptionState& exception_state) { | 101 ExceptionState& exception_state) { |
17 if ((x->GetType() != CSSStyleValue::StyleValueType::kLengthType && | 102 if (!IsLengthOrPercent(x) || !IsLengthOrPercent(y)) { |
18 x->GetType() != CSSStyleValue::StyleValueType::kPercentType) || | |
19 (y->GetType() != CSSStyleValue::StyleValueType::kLengthType && | |
20 y->GetType() != CSSStyleValue::StyleValueType::kPercentType)) { | |
21 exception_state.ThrowTypeError( | 103 exception_state.ThrowTypeError( |
22 "Must pass length or percentage to X and Y of CSSTranslation"); | 104 "Must pass length or percentage to X and Y of CSSTranslation"); |
23 return nullptr; | 105 return nullptr; |
24 } | 106 } |
25 return new CSSTranslation( | 107 return new CSSTranslation( |
26 x, y, CSSUnitValue::Create(0, CSSPrimitiveValue::UnitType::kPixels), | 108 x, y, CSSUnitValue::Create(0, CSSPrimitiveValue::UnitType::kPixels), |
27 true /* is2D */); | 109 true /* is2D */); |
28 } | 110 } |
29 | 111 |
30 CSSTranslation* CSSTranslation::Create(CSSNumericValue* x, | 112 CSSTranslation* CSSTranslation::Create(CSSNumericValue* x, |
31 CSSNumericValue* y, | 113 CSSNumericValue* y, |
32 CSSNumericValue* z, | 114 CSSNumericValue* z, |
33 ExceptionState& exception_state) { | 115 ExceptionState& exception_state) { |
34 if ((x->GetType() != CSSStyleValue::StyleValueType::kLengthType && | 116 if (!IsLengthOrPercent(x) || !IsLengthOrPercent(y)) { |
35 x->GetType() != CSSStyleValue::StyleValueType::kPercentType) || | |
36 (y->GetType() != CSSStyleValue::StyleValueType::kLengthType && | |
37 y->GetType() != CSSStyleValue::StyleValueType::kPercentType)) { | |
38 exception_state.ThrowTypeError( | 117 exception_state.ThrowTypeError( |
39 "Must pass length or percentage to X and Y of CSSTranslation"); | 118 "Must pass length or percentage to X and Y of CSSTranslation"); |
40 return nullptr; | 119 return nullptr; |
41 } | 120 } |
42 if (z && z->GetType() != CSSStyleValue::StyleValueType::kLengthType) { | 121 if (z && z->GetType() != CSSStyleValue::StyleValueType::kLengthType) { |
43 exception_state.ThrowTypeError("Must pass length to Z of CSSTranslation"); | 122 exception_state.ThrowTypeError("Must pass length to Z of CSSTranslation"); |
44 return nullptr; | 123 return nullptr; |
45 } | 124 } |
46 if (z && z->ContainsPercent()) { | 125 if (z && z->ContainsPercent()) { |
47 exception_state.ThrowTypeError( | 126 exception_state.ThrowTypeError( |
48 "CSSTranslation does not support z CSSNumericValue with percent units"); | 127 "CSSTranslation does not support z CSSNumericValue with percent units"); |
49 return nullptr; | 128 return nullptr; |
50 } | 129 } |
51 return new CSSTranslation(x, y, z, false /* is2D */); | 130 return new CSSTranslation(x, y, z, false /* is2D */); |
52 } | 131 } |
53 | 132 |
| 133 CSSTranslation* CSSTranslation::Create(CSSNumericValue* x, CSSNumericValue* y) { |
| 134 DCHECK(IsLengthOrPercent(x)); |
| 135 DCHECK(IsLengthOrPercent(y)); |
| 136 return new CSSTranslation( |
| 137 x, y, CSSUnitValue::Create(0, CSSPrimitiveValue::UnitType::kPixels), |
| 138 true /* is2D */); |
| 139 } |
| 140 |
| 141 CSSTranslation* CSSTranslation::Create(CSSNumericValue* x, |
| 142 CSSNumericValue* y, |
| 143 CSSNumericValue* z) { |
| 144 DCHECK(IsLengthOrPercent(x)); |
| 145 DCHECK(IsLengthOrPercent(y)); |
| 146 DCHECK_EQ(z->GetType(), CSSStyleValue::StyleValueType::kLengthType); |
| 147 DCHECK(!z->ContainsPercent()); |
| 148 return new CSSTranslation(x, y, z, false /* is2D */); |
| 149 } |
| 150 |
| 151 CSSTranslation* CSSTranslation::FromCSSValue(const CSSFunctionValue& value) { |
| 152 switch (value.FunctionType()) { |
| 153 case CSSValueTranslateX: |
| 154 case CSSValueTranslateY: |
| 155 case CSSValueTranslateZ: |
| 156 return FromCSSTranslateXYZ(value); |
| 157 case CSSValueTranslate: |
| 158 return FromCSSTranslate(value); |
| 159 case CSSValueTranslate3d: |
| 160 return FromCSSTranslate3D(value); |
| 161 default: |
| 162 NOTREACHED(); |
| 163 return nullptr; |
| 164 } |
| 165 } |
| 166 |
54 void CSSTranslation::setX(CSSNumericValue* x, ExceptionState& exception_state) { | 167 void CSSTranslation::setX(CSSNumericValue* x, ExceptionState& exception_state) { |
55 if (x->GetType() != CSSStyleValue::StyleValueType::kLengthType && | 168 if (x->GetType() != CSSStyleValue::StyleValueType::kLengthType && |
56 x->GetType() != CSSStyleValue::StyleValueType::kPercentType) { | 169 x->GetType() != CSSStyleValue::StyleValueType::kPercentType) { |
57 exception_state.ThrowTypeError( | 170 exception_state.ThrowTypeError( |
58 "Must pass length or percentage to X of CSSTranslation"); | 171 "Must pass length or percentage to X of CSSTranslation"); |
59 return; | 172 return; |
60 } | 173 } |
61 x_ = x; | 174 x_ = x; |
62 } | 175 } |
63 | 176 |
64 void CSSTranslation::setY(CSSNumericValue* y, ExceptionState& exception_state) { | 177 void CSSTranslation::setY(CSSNumericValue* y, ExceptionState& exception_state) { |
65 if (y->GetType() != CSSStyleValue::StyleValueType::kLengthType && | 178 if (y->GetType() != CSSStyleValue::StyleValueType::kLengthType && |
66 y->GetType() != CSSStyleValue::StyleValueType::kPercentType) { | 179 y->GetType() != CSSStyleValue::StyleValueType::kPercentType) { |
67 exception_state.ThrowTypeError( | 180 exception_state.ThrowTypeError( |
68 "Must pass length or percent to Y of CSSTranslation"); | 181 "Must pass length or percent to Y of CSSTranslation"); |
69 return; | 182 return; |
70 } | 183 } |
71 y_ = y; | 184 y_ = y; |
72 } | 185 } |
73 | 186 |
74 void CSSTranslation::setZ(CSSNumericValue* z, ExceptionState& exception_state) { | 187 void CSSTranslation::setZ(CSSNumericValue* z, ExceptionState& exception_state) { |
75 if (z && z->GetType() != CSSStyleValue::StyleValueType::kLengthType) { | 188 if (z->GetType() != CSSStyleValue::StyleValueType::kLengthType) { |
76 exception_state.ThrowTypeError("Must pass length to Z of CSSTranslation"); | 189 exception_state.ThrowTypeError("Must pass length to Z of CSSTranslation"); |
77 return; | 190 return; |
78 } | 191 } |
79 if (z && z->ContainsPercent()) { | 192 if (z->ContainsPercent()) { |
80 exception_state.ThrowTypeError( | 193 exception_state.ThrowTypeError( |
81 "CSSTranslation does not support z CSSNumericValue with percent units"); | 194 "CSSTranslation does not support z CSSNumericValue with percent units"); |
82 return; | 195 return; |
83 } | 196 } |
84 z_ = z; | 197 z_ = z; |
85 } | 198 } |
86 | 199 |
| 200 DOMMatrix* CSSTranslation::AsMatrix() const { |
| 201 CSSUnitValue* x = x_->to(CSSPrimitiveValue::UnitType::kPixels); |
| 202 CSSUnitValue* y = y_->to(CSSPrimitiveValue::UnitType::kPixels); |
| 203 CSSUnitValue* z = z_->to(CSSPrimitiveValue::UnitType::kPixels); |
| 204 // TODO(meade): What should happen when the translation contains relative |
| 205 // lengths here? |
| 206 // https://github.com/w3c/css-houdini-drafts/issues/421 |
| 207 if (!x || !y || !z) |
| 208 return nullptr; |
| 209 |
| 210 DOMMatrix* matrix = DOMMatrix::Create(); |
| 211 return matrix->translate(x->value(), y->value(), z->value()); |
| 212 } |
| 213 |
87 CSSFunctionValue* CSSTranslation::ToCSSValue() const { | 214 CSSFunctionValue* CSSTranslation::ToCSSValue() const { |
88 CSSFunctionValue* result = CSSFunctionValue::Create( | 215 CSSFunctionValue* result = CSSFunctionValue::Create( |
89 is2D() ? CSSValueTranslate : CSSValueTranslate3d); | 216 is2D() ? CSSValueTranslate : CSSValueTranslate3d); |
90 result->Append(*x_->ToCSSValue()); | 217 result->Append(*x_->ToCSSValue()); |
91 result->Append(*y_->ToCSSValue()); | 218 result->Append(*y_->ToCSSValue()); |
92 if (!is2D()) | 219 if (!is2D()) |
93 result->Append(*z_->ToCSSValue()); | 220 result->Append(*z_->ToCSSValue()); |
94 return result; | 221 return result; |
95 } | 222 } |
96 | 223 |
97 } // namespace blink | 224 } // namespace blink |
OLD | NEW |