Browse Source

Transforms: Disallow percentages in perspective and translateZ

In accordance with the CSS specs.
Michael Ragazzon 2 years ago
parent
commit
131a963fe8

+ 2 - 2
Samples/basic/transform/src/main.cpp

@@ -63,7 +63,7 @@ public:
 		{
 			std::stringstream s;
 			s << "perspective(" << perspective << "dp) ";
-			document->SetProperty("transform", s.str().c_str());
+			document->SetProperty("transform", s.str());
 		}
 	}
 
@@ -75,7 +75,7 @@ public:
 			if (perspective > 0)
 				s << "perspective(" << perspective << "dp) ";
 			s << "rotate3d(0.0, 1.0, 0.0, " << degrees << "deg)";
-			document->SetProperty("transform", s.str().c_str());
+			document->SetProperty("transform", s.str());
 		}
 	}
 

+ 34 - 29
Source/Core/PropertyParserTransform.cpp

@@ -34,7 +34,9 @@
 
 namespace Rml {
 
-PropertyParserTransform::PropertyParserTransform() : number(Unit::NUMBER), length(Unit::LENGTH_PERCENT, Unit::PX), angle(Unit::ANGLE, Unit::RAD) {}
+PropertyParserTransform::PropertyParserTransform() :
+	number(Unit::NUMBER), length(Unit::LENGTH, Unit::PX), length_pct(Unit::LENGTH_PERCENT, Unit::PX), angle(Unit::ANGLE, Unit::RAD)
+{}
 
 PropertyParserTransform::~PropertyParserTransform() {}
 
@@ -53,18 +55,21 @@ bool PropertyParserTransform::ParseValue(Property& property, const String& value
 
 	NumericValue args[16];
 
-	const PropertyParser* angle1[] = {&angle};
-	const PropertyParser* angle2[] = {&angle, &angle};
-	const PropertyParser* length1[] = {&length};
-	const PropertyParser* length2[] = {&length, &length};
-	const PropertyParser* length3[] = {&length, &length, &length};
-	const PropertyParser* number3angle1[] = {&number, &number, &number, &angle};
-	const PropertyParser* number1[] = {&number};
-	const PropertyParser* number2[] = {&number, &number};
-	const PropertyParser* number3[] = {&number, &number, &number};
-	const PropertyParser* number6[] = {&number, &number, &number, &number, &number, &number};
 	const PropertyParser* number16[] = {&number, &number, &number, &number, &number, &number, &number, &number, &number, &number, &number, &number,
 		&number, &number, &number, &number};
+	const PropertyParser* lengthpct2_length1[] = {&length_pct, &length_pct, &length};
+	const PropertyParser* number3angle1[] = {&number, &number, &number, &angle};
+	const PropertyParser* angle2[] = {&angle, &angle};
+	const PropertyParser* length1[] = {&length};
+
+	// For semantic purposes, define subsets of the above parsers when scanning primitives below.
+	auto lengthpct1 = lengthpct2_length1;
+	auto lengthpct2 = lengthpct2_length1;
+	auto angle1 = angle2;
+	auto number1 = number16;
+	auto number2 = number16;
+	auto number3 = number16;
+	auto number6 = number16;
 
 	while (*next)
 	{
@@ -83,11 +88,11 @@ bool PropertyParserTransform::ParseValue(Property& property, const String& value
 		{
 			transform->AddPrimitive({Matrix3D(args)});
 		}
-		else if (Scan(bytes_read, next, "translateX", length1, args, 1))
+		else if (Scan(bytes_read, next, "translateX", lengthpct1, args, 1))
 		{
 			transform->AddPrimitive({TranslateX(args)});
 		}
-		else if (Scan(bytes_read, next, "translateY", length1, args, 1))
+		else if (Scan(bytes_read, next, "translateY", lengthpct1, args, 1))
 		{
 			transform->AddPrimitive({TranslateY(args)});
 		}
@@ -95,11 +100,11 @@ bool PropertyParserTransform::ParseValue(Property& property, const String& value
 		{
 			transform->AddPrimitive({TranslateZ(args)});
 		}
-		else if (Scan(bytes_read, next, "translate", length2, args, 2))
+		else if (Scan(bytes_read, next, "translate", lengthpct2, args, 2))
 		{
 			transform->AddPrimitive({Translate2D(args)});
 		}
-		else if (Scan(bytes_read, next, "translate3d", length3, args, 3))
+		else if (Scan(bytes_read, next, "translate3d", lengthpct2_length1, args, 3))
 		{
 			transform->AddPrimitive({Translate3D(args)});
 		}
@@ -183,20 +188,6 @@ bool PropertyParserTransform::Scan(int& out_bytes_read, const char* str, const c
 	out_bytes_read = 0;
 	int total_bytes_read = 0, bytes_read = 0;
 
-	/* use the quicker stack-based argument buffer, if possible */
-	char* arg = nullptr;
-	char arg_stack[1024];
-	String arg_heap;
-	if (strlen(str) < sizeof(arg_stack))
-	{
-		arg = arg_stack;
-	}
-	else
-	{
-		arg_heap = str;
-		arg = &arg_heap[0];
-	}
-
 	/* skip leading white space */
 	bytes_read = 0;
 	sscanf(str, " %n", &bytes_read);
@@ -233,6 +224,20 @@ bool PropertyParserTransform::Scan(int& out_bytes_read, const char* str, const c
 		return false;
 	}
 
+	/* use the quicker stack-based argument buffer, if possible */
+	char* arg = nullptr;
+	char arg_stack[1024];
+	String arg_heap;
+	if (strlen(str) < sizeof(arg_stack))
+	{
+		arg = arg_stack;
+	}
+	else
+	{
+		arg_heap = str;
+		arg = &arg_heap[0];
+	}
+
 	/* parse the arguments */
 	for (int i = 0; i < nargs; ++i)
 	{

+ 1 - 1
Source/Core/PropertyParserTransform.h

@@ -62,7 +62,7 @@ private:
 	/// @return True if parsed successfully, false otherwise.
 	bool Scan(int& out_bytes_read, const char* str, const char* keyword, const PropertyParser** parsers, NumericValue* args, int nargs) const;
 
-	PropertyParserNumber number, length, angle;
+	PropertyParserNumber number, length, length_pct, angle;
 };
 
 } // namespace Rml

+ 8 - 9
Source/Core/TransformUtilities.cpp

@@ -85,13 +85,12 @@ static inline float ResolveHeight(NumericValue value, Element& e) noexcept
 	return e.ResolveNumericValue(value, e.GetBox().GetSize(BoxArea::Border).y);
 }
 
-// Resolve a numeric property value with the element's depth as relative base value.
-static inline float ResolveDepth(NumericValue value, Element& e) noexcept
+// Resolve a length numeric property value for the given element.
+static inline float ResolveLength(NumericValue value, Element& e) noexcept
 {
 	if (value.unit == Unit::PX || value.unit == Unit::NUMBER)
 		return value.number;
-	Vector2f size = e.GetBox().GetSize(BoxArea::Border);
-	return e.ResolveNumericValue(value, Math::Max(size.x, size.y));
+	return e.ResolveLength(value);
 }
 
 static inline String ToString(NumericValue value) noexcept
@@ -192,11 +191,11 @@ struct ResolveTransformVisitor {
 
 	void operator()(const Transforms::TranslateX& p) { m = Matrix4f::TranslateX(ResolveWidth(p.values[0], e)); }
 	void operator()(const Transforms::TranslateY& p) { m = Matrix4f::TranslateY(ResolveHeight(p.values[0], e)); }
-	void operator()(const Transforms::TranslateZ& p) { m = Matrix4f::TranslateZ(ResolveDepth(p.values[0], e)); }
+	void operator()(const Transforms::TranslateZ& p) { m = Matrix4f::TranslateZ(ResolveLength(p.values[0], e)); }
 	void operator()(const Transforms::Translate2D& p) { m = Matrix4f::Translate(ResolveWidth(p.values[0], e), ResolveHeight(p.values[1], e), 0); }
 	void operator()(const Transforms::Translate3D& p)
 	{
-		m = Matrix4f::Translate(ResolveWidth(p.values[0], e), ResolveHeight(p.values[1], e), ResolveDepth(p.values[2], e));
+		m = Matrix4f::Translate(ResolveWidth(p.values[0], e), ResolveHeight(p.values[1], e), ResolveLength(p.values[2], e));
 	}
 
 	void operator()(const Transforms::ScaleX& p) { m = Matrix4f::ScaleX(p.values[0]); }
@@ -216,7 +215,7 @@ struct ResolveTransformVisitor {
 	void operator()(const Transforms::Skew2D& p) { m = Matrix4f::Skew(p.values[0], p.values[1]); }
 
 	void operator()(const Transforms::DecomposedMatrix4& p) { m = Matrix4f::Compose(p.translation, p.scale, p.skew, p.perspective, p.quaternion); }
-	void operator()(const Transforms::Perspective& p) { m = Matrix4f::Perspective(ResolveDepth(p.values[0], e)); }
+	void operator()(const Transforms::Perspective& p) { m = Matrix4f::Perspective(ResolveLength(p.values[0], e)); }
 
 	void run(const TransformPrimitive& primitive)
 	{
@@ -271,7 +270,7 @@ struct PrepareVisitor {
 	}
 	bool operator()(TranslateZ& p)
 	{
-		p.values[0] = NumericValue{ResolveDepth(p.values[0], e), Unit::PX};
+		p.values[0] = NumericValue{ResolveLength(p.values[0], e), Unit::PX};
 		return true;
 	}
 	bool operator()(Translate2D& p)
@@ -284,7 +283,7 @@ struct PrepareVisitor {
 	{
 		p.values[0] = NumericValue{ResolveWidth(p.values[0], e), Unit::PX};
 		p.values[1] = NumericValue{ResolveHeight(p.values[1], e), Unit::PX};
-		p.values[2] = NumericValue{ResolveDepth(p.values[2], e), Unit::PX};
+		p.values[2] = NumericValue{ResolveLength(p.values[2], e), Unit::PX};
 		return true;
 	}
 	template <size_t N>