Parcourir la source

Add 'clip: always' property value, make the clip property non-inherited. See #235.

Michael Ragazzon il y a 4 ans
Parent
commit
8a022972f4

+ 11 - 4
Include/RmlUi/Core/ComputedValues.h

@@ -99,11 +99,18 @@ struct VerticalAlign {
 
 
 enum class Overflow : uint8_t { Visible, Hidden, Auto, Scroll };
 enum class Overflow : uint8_t { Visible, Hidden, Auto, Scroll };
 struct Clip {
 struct Clip {
-	enum class Type : uint8_t { Auto, None, Number };
-	// Note, internally 'number' is encoded with Auto as 0 and None as -1. However, the enum must correspond to the keywords in StyleSheetSpec.
-	int number = 0;
+private:
+	// Here, 'value' is encoded with Auto <=> 0, None <=> -1, Always <=> -2. A value > 0 means the given number.
+	int8_t value = 0;
+
+public:
+	// The Type enum must instead correspond to the keywords in StyleSheetSpec.
+	enum class Type : uint8_t { Auto, None, Always, Number };
 	Clip() {}
 	Clip() {}
-	Clip(Type type, int number = 0) : number(type == Type::Auto ? 0 : (type == Type::None ? -1 : number)) {}
+	Clip(Type type, int8_t number = 0) : value(type == Type::Auto ? 0 : (type == Type::None ? -1 : (type == Type::Always ? -2 : number))) {}
+	int GetNumber() const { return value < 0 ? 0 : value; }
+	Type GetType() const { return value == 0 ? Type::Auto : (value == -1 ? Type::None : (value == -2 ? Type::Always : Type::Number)); }
+	bool operator==(Type type) const { return GetType() == type; }
 };
 };
 
 
 enum class Visibility : uint8_t { Visible, Hidden };
 enum class Visibility : uint8_t { Visible, Hidden };

+ 0 - 5
Include/RmlUi/Core/Element.h

@@ -566,11 +566,6 @@ public:
 	DataModel* GetDataModel() const;
 	DataModel* GetDataModel() const;
 	//@}
 	//@}
 	
 	
-	/// Returns true if this element requires clipping
-	int GetClippingIgnoreDepth();
-	/// Returns true if this element has clipping enabled
-	bool IsClippingEnabled();
-
 	/// Gets the render interface owned by this element's context.
 	/// Gets the render interface owned by this element's context.
 	/// @return The element's context's render interface.
 	/// @return The element's context's render interface.
 	RenderInterface* GetRenderInterface();
 	RenderInterface* GetRenderInterface();

+ 2 - 2
Source/Core/ComputeProperty.cpp

@@ -214,11 +214,11 @@ float ComputeFontsize(const Property& property, const Style::ComputedValues& val
 
 
 Style::Clip ComputeClip(const Property* property)
 Style::Clip ComputeClip(const Property* property)
 {
 {
-	int value = property->Get<int>();
+	const int value = property->Get<int>();
 	if (property->unit == Property::KEYWORD)
 	if (property->unit == Property::KEYWORD)
 		return Style::Clip(static_cast<Style::Clip::Type>(value));
 		return Style::Clip(static_cast<Style::Clip::Type>(value));
 	else if (property->unit == Property::NUMBER)
 	else if (property->unit == Property::NUMBER)
-		return Style::Clip(Style::Clip::Type::Number, value);
+		return Style::Clip(Style::Clip::Type::Number, static_cast<int8_t>(value));
 	RMLUI_ERRORMSG("Invalid clip type");
 	RMLUI_ERRORMSG("Invalid clip type");
 	return Style::Clip();
 	return Style::Clip();
 }
 }

+ 0 - 11
Source/Core/Element.cpp

@@ -1596,17 +1596,6 @@ DataModel* Element::GetDataModel() const
 {
 {
 	return data_model;
 	return data_model;
 }
 }
-	
-int Element::GetClippingIgnoreDepth()
-{
-	return GetComputedValues().clip.number;
-}
-	
-bool Element::IsClippingEnabled()
-{
-	const auto& computed = GetComputedValues();
-	return computed.overflow_x != Style::Overflow::Visible || computed.overflow_y != Style::Overflow::Visible;
-}
 
 
 // Gets the render interface owned by this element's context.
 // Gets the render interface owned by this element's context.
 RenderInterface* Element::GetRenderInterface()
 RenderInterface* Element::GetRenderInterface()

+ 0 - 2
Source/Core/ElementStyle.cpp

@@ -620,8 +620,6 @@ PropertyIdSet ElementStyle::ComputeValues(Style::ComputedValues& values, const S
 	{
 	{
 		// Inherited properties are copied here, but may be overwritten below by locally defined properties
 		// Inherited properties are copied here, but may be overwritten below by locally defined properties
 		// Line-height and font-size are computed above
 		// Line-height and font-size are computed above
-		values.clip = parent_values->clip;
-		
 		values.color = parent_values->color;
 		values.color = parent_values->color;
 		values.opacity = parent_values->opacity;
 		values.opacity = parent_values->opacity;
 
 

+ 25 - 23
Source/Core/ElementUtilities.cpp

@@ -166,13 +166,16 @@ int ElementUtilities::GetStringWidth(Element* element, const String& string, Cha
 // Generates the clipping region for an element.
 // Generates the clipping region for an element.
 bool ElementUtilities::GetClippingRegion(Vector2i& clip_origin, Vector2i& clip_dimensions, Element* element)
 bool ElementUtilities::GetClippingRegion(Vector2i& clip_origin, Vector2i& clip_dimensions, Element* element)
 {
 {
+	using Style::Clip;
 	clip_origin = Vector2i(-1, -1);
 	clip_origin = Vector2i(-1, -1);
 	clip_dimensions = Vector2i(-1, -1);
 	clip_dimensions = Vector2i(-1, -1);
-	
-	int num_ignored_clips = element->GetClippingIgnoreDepth();
-	if (num_ignored_clips < 0)
+
+	Clip target_element_clip = element->GetComputedValues().clip;
+	if (target_element_clip == Clip::Type::None)
 		return false;
 		return false;
 
 
+	int num_ignored_clips = target_element_clip.GetNumber();
+
 	// Search through the element's ancestors, finding all elements that clip their overflow and have overflow to clip.
 	// Search through the element's ancestors, finding all elements that clip their overflow and have overflow to clip.
 	// For each that we find, we combine their clipping region with the existing clipping region, and so build up a
 	// For each that we find, we combine their clipping region with the existing clipping region, and so build up a
 	// complete clipping region for the element.
 	// complete clipping region for the element.
@@ -180,19 +183,26 @@ bool ElementUtilities::GetClippingRegion(Vector2i& clip_origin, Vector2i& clip_d
 
 
 	while (clipping_element != nullptr)
 	while (clipping_element != nullptr)
 	{
 	{
+		const ComputedValues& clip_computed = clipping_element->GetComputedValues();
+		const bool clip_enabled = (clip_computed.overflow_x != Style::Overflow::Visible || clip_computed.overflow_y != Style::Overflow::Visible);
+		const bool clip_always = (clip_computed.clip == Clip::Type::Always);
+		const bool clip_none = (clip_computed.clip == Clip::Type::None);
+		const int clip_number = clip_computed.clip.GetNumber();
+
+		// If this region ignores all clipping regions, then we do too.
+		if (clip_none)
+			break;
+
 		// Merge the existing clip region with the current clip region if we aren't ignoring clip regions.
 		// Merge the existing clip region with the current clip region if we aren't ignoring clip regions.
-		if (num_ignored_clips == 0 && clipping_element->IsClippingEnabled())
+		if (clip_always || (num_ignored_clips == 0 && clip_enabled))
 		{
 		{
 			// Ignore nodes that don't clip.
 			// Ignore nodes that don't clip.
-			if (clipping_element->GetClientWidth() < clipping_element->GetScrollWidth() - 0.5f
-				|| clipping_element->GetClientHeight() < clipping_element->GetScrollHeight() - 0.5f)
+			if (clip_always || clipping_element->GetClientWidth() < clipping_element->GetScrollWidth() - 0.5f ||
+				clipping_element->GetClientHeight() < clipping_element->GetScrollHeight() - 0.5f)
 			{
 			{
 				const Box::Area client_area = clipping_element->GetClientArea();
 				const Box::Area client_area = clipping_element->GetClientArea();
-				const Vector2f element_origin_f = clipping_element->GetAbsoluteOffset(client_area);
-				const Vector2f element_dimensions_f = clipping_element->GetBox().GetSize(client_area);
-				
-				const Vector2i element_origin(Math::RealToInteger(element_origin_f.x), Math::RealToInteger(element_origin_f.y));
-				const Vector2i element_dimensions(Math::RealToInteger(element_dimensions_f.x), Math::RealToInteger(element_dimensions_f.y));
+				const Vector2i element_origin(clipping_element->GetAbsoluteOffset(client_area));
+				const Vector2i element_dimensions(clipping_element->GetBox().GetSize(client_area));
 				
 				
 				if (clip_origin == Vector2i(-1, -1) && clip_dimensions == Vector2i(-1, -1))
 				if (clip_origin == Vector2i(-1, -1) && clip_dimensions == Vector2i(-1, -1))
 				{
 				{
@@ -215,19 +225,11 @@ bool ElementUtilities::GetClippingRegion(Vector2i& clip_origin, Vector2i& clip_d
 		}
 		}
 
 
 		// If this region is meant to clip and we're skipping regions, update the counter.
 		// If this region is meant to clip and we're skipping regions, update the counter.
-		if (num_ignored_clips > 0)
-		{
-			if (clipping_element->IsClippingEnabled())
-				num_ignored_clips--;
-		}
-
-		// Determine how many clip regions this ancestor ignores, and inherit the value. If this region ignores all
-		// clipping regions, then we do too.
-		int clipping_element_ignore_clips = clipping_element->GetClippingIgnoreDepth();
-		if (clipping_element_ignore_clips < 0)
-			break;
+		if (num_ignored_clips > 0 && clip_enabled)
+			num_ignored_clips--;
 		
 		
-		num_ignored_clips = Math::Max(num_ignored_clips, clipping_element_ignore_clips);
+		// Inherit how many clip regions this ancestor ignores.
+		num_ignored_clips = Math::Max(num_ignored_clips, clip_number);
 
 
 		// Climb the tree to this region's parent.
 		// Climb the tree to this region's parent.
 		clipping_element = clipping_element->GetParentNode();
 		clipping_element = clipping_element->GetParentNode();

+ 1 - 1
Source/Core/StyleSheetSpecification.cpp

@@ -363,7 +363,7 @@ void StyleSheetSpecification::RegisterDefaultProperties()
 	RegisterProperty(PropertyId::OverflowX, "overflow-x", "visible", false, true).AddParser("keyword", "visible, hidden, auto, scroll");
 	RegisterProperty(PropertyId::OverflowX, "overflow-x", "visible", false, true).AddParser("keyword", "visible, hidden, auto, scroll");
 	RegisterProperty(PropertyId::OverflowY, "overflow-y", "visible", false, true).AddParser("keyword", "visible, hidden, auto, scroll");
 	RegisterProperty(PropertyId::OverflowY, "overflow-y", "visible", false, true).AddParser("keyword", "visible, hidden, auto, scroll");
 	RegisterShorthand(ShorthandId::Overflow, "overflow", "overflow-x, overflow-y", ShorthandType::Replicate);
 	RegisterShorthand(ShorthandId::Overflow, "overflow", "overflow-x, overflow-y", ShorthandType::Replicate);
-	RegisterProperty(PropertyId::Clip, "clip", "auto", true, false).AddParser("keyword", "auto, none").AddParser("number");
+	RegisterProperty(PropertyId::Clip, "clip", "auto", false, false).AddParser("keyword", "auto, none, always").AddParser("number");
 	RegisterProperty(PropertyId::Visibility, "visibility", "visible", false, false).AddParser("keyword", "visible, hidden");
 	RegisterProperty(PropertyId::Visibility, "visibility", "visible", false, false).AddParser("keyword", "visible, hidden");
 
 
 	// Need some work on this if we are to include images.
 	// Need some work on this if we are to include images.

+ 27 - 1
Tests/Data/VisualTests/overflow_hidden.rml

@@ -17,11 +17,18 @@
 			border: 1dp black;
 			border: 1dp black;
 			overflow: hidden;
 			overflow: hidden;
 			width: 200dp;
 			width: 200dp;
-			height: 200dp;
+			height: 120dp;
+			margin: 10dp 0;
 		}
 		}
 		div.relative {
 		div.relative {
 			position: relative;
 			position: relative;
 		}
 		}
+		div.clip-always {
+			clip: always;
+		}
+		div.clip-none {
+			clip: none;
+		}
 		div.wide {
 		div.wide {
 			width: 300dp;
 			width: 300dp;
 			height: 20dp;
 			height: 20dp;
@@ -36,6 +43,10 @@
 			width: 80dp;
 			width: 80dp;
 			height: 80dp;
 			height: 80dp;
 		}
 		}
+		div.close {
+			top: 20dp;
+			left: 250dp;
+		}
 		.green { background-color: #7f7; }
 		.green { background-color: #7f7; }
 		.red { background-color: #f77; }
 		.red { background-color: #f77; }
 	</style>
 	</style>
@@ -67,5 +78,20 @@
 		LONG_WOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOORD&nbsp;FAIL
 		LONG_WOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOORD&nbsp;FAIL
 	</div>
 	</div>
 </div>
 </div>
+<div class="overflow relative">
+	LONG_WOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOORD&nbsp;FAIL
+	<div class="absolute close red" style="top: 0">Should not be visible</div>
+	<div class="clip-none">
+		Don't clip within a clipping parent using 'clip: none'.
+		LONG_WOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOORD
+		<div class="absolute close green">Should be visible</div>
+	</div>
+</div>
+<div class="overflow relative clip-always">
+	Force clipping even though contents don't overflow using 'clip: always'.
+	<div>
+		<div class="absolute close red">Should not be visible</div>
+	</div>
+</div>
 </body>
 </body>
 </rml>
 </rml>

+ 24 - 1
Tests/Data/VisualTests/reference/overflow_hidden-ref.rml

@@ -12,11 +12,18 @@
 			border: 1dp black;
 			border: 1dp black;
 			overflow: hidden;
 			overflow: hidden;
 			width: 200dp;
 			width: 200dp;
-			height: 200dp;
+			height: 120dp;
+			margin: 10dp 0;
 		}
 		}
 		div.relative {
 		div.relative {
 			position: relative;
 			position: relative;
 		}
 		}
+		div.clip-always {
+			clip: always;
+		}
+		div.clip-none {
+			clip: none;
+		}
 		div.wide {
 		div.wide {
 			width: 300dp;
 			width: 300dp;
 			height: 20dp;
 			height: 20dp;
@@ -31,6 +38,10 @@
 			width: 80dp;
 			width: 80dp;
 			height: 80dp;
 			height: 80dp;
 		}
 		}
+		div.close {
+			top: 20dp;
+			left: 250dp;
+		}
 		.green { background-color: #7f7; }
 		.green { background-color: #7f7; }
 		.red { background-color: #f77; }
 		.red { background-color: #f77; }
 	</style>
 	</style>
@@ -56,5 +67,17 @@
 		LONG_WOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOORD&nbsp;FAIL
 		LONG_WOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOORD&nbsp;FAIL
 	</div>
 	</div>
 </div>
 </div>
+<div class="overflow relative" style="overflow: visible">
+	<div style="overflow: hidden">
+		LONG_WOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOORD&nbsp;FAIL
+		<div class="absolute close red">Should not be visible</div>
+	</div>
+		Don't clip within a clipping parent using 'clip: none'.
+	LONG_WOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOORD
+	<div class="absolute close green">Should be visible</div>
+</div>
+<div class="overflow">
+	Force clipping even though contents don't overflow using 'clip: always'.
+</div>
 </body>
 </body>
 </rml>
 </rml>