Browse Source

Allow decorators to specify paint area [breaking change]

Breaking change: 'Decorator::GenerateElementData()' has a new paint area parameter.
Michael Ragazzon 2 years ago
parent
commit
c3622e669c

+ 2 - 1
Include/RmlUi/Core/Decorator.h

@@ -57,8 +57,9 @@ public:
 
 
 	/// Called on a decorator to generate any required per-element data for a newly decorated element.
 	/// Called on a decorator to generate any required per-element data for a newly decorated element.
 	/// @param[in] element The newly decorated element.
 	/// @param[in] element The newly decorated element.
+	/// @param[in] paint_area Determines the element's area to be painted by the decorator.
 	/// @return A handle to a decorator-defined data handle, or nullptr if none is needed for the element.
 	/// @return A handle to a decorator-defined data handle, or nullptr if none is needed for the element.
-	virtual DecoratorDataHandle GenerateElementData(Element* element) const = 0;
+	virtual DecoratorDataHandle GenerateElementData(Element* element, BoxArea paint_area) const = 0;
 	/// Called to release element data generated by this decorator.
 	/// Called to release element data generated by this decorator.
 	/// @param[in] element_data The element data handle to release.
 	/// @param[in] element_data The element data handle to release.
 	virtual void ReleaseElementData(DecoratorDataHandle element_data) const = 0;
 	virtual void ReleaseElementData(DecoratorDataHandle element_data) const = 0;

+ 1 - 0
Include/RmlUi/Core/StyleSheetTypes.h

@@ -63,6 +63,7 @@ struct DecoratorDeclaration {
 	String type;
 	String type;
 	DecoratorInstancer* instancer;
 	DecoratorInstancer* instancer;
 	PropertyDictionary properties;
 	PropertyDictionary properties;
+	BoxArea paint_area;
 };
 };
 struct DecoratorDeclarationList {
 struct DecoratorDeclarationList {
 	Vector<DecoratorDeclaration> list;
 	Vector<DecoratorDeclaration> list;

+ 1 - 1
Samples/basic/effect/data/effect.rml

@@ -63,7 +63,7 @@
 
 
 .transform, .filter.transform_all > .box { transform: rotate3d(0.2, 0.4, 0.1, 15deg); }
 .transform, .filter.transform_all > .box { transform: rotate3d(0.2, 0.4, 0.1, 15deg); }
 
 
-.gradient { decorator: linear-gradient(110deg, #fff3, #fff 10%, #c33 250dp, #3c3, #33c, #000 90%, #0003); }
+.gradient { decorator: linear-gradient(110deg, #fff3, #fff 10%, #c33 250dp, #3c3, #33c, #000 90%, #0003) border-box; }
 
 
 .brightness { filter: brightness(0.5); }
 .brightness { filter: brightness(0.5); }
 .contrast { filter: contrast(0.5); }
 .contrast { filter: contrast(0.5); }

+ 1 - 1
Samples/invaders/src/DecoratorDefender.cpp

@@ -49,7 +49,7 @@ bool DecoratorDefender::Initialise(const Rml::Texture& texture)
 	return true;
 	return true;
 }
 }
 
 
-Rml::DecoratorDataHandle DecoratorDefender::GenerateElementData(Rml::Element* /*element*/) const
+Rml::DecoratorDataHandle DecoratorDefender::GenerateElementData(Rml::Element* /*element*/, Rml::BoxArea /*paint_area*/) const
 {
 {
 	return Rml::Decorator::INVALID_DECORATORDATAHANDLE;
 	return Rml::Decorator::INVALID_DECORATORDATAHANDLE;
 }
 }

+ 1 - 6
Samples/invaders/src/DecoratorDefender.h

@@ -38,16 +38,11 @@ public:
 	bool Initialise(const Rml::Texture& texture);
 	bool Initialise(const Rml::Texture& texture);
 
 
 	/// Called on a decorator to generate any required per-element data for a newly decorated element.
 	/// Called on a decorator to generate any required per-element data for a newly decorated element.
-	/// @param element[in] The newly decorated element.
-	/// @return A handle to a decorator-defined data handle, or nullptr if none is needed for the element.
-	Rml::DecoratorDataHandle GenerateElementData(Rml::Element* element) const override;
+	Rml::DecoratorDataHandle GenerateElementData(Rml::Element* element, Rml::BoxArea paint_area) const override;
 	/// Called to release element data generated by this decorator.
 	/// Called to release element data generated by this decorator.
-	/// @param element_data[in] The element data handle to release.
 	void ReleaseElementData(Rml::DecoratorDataHandle element_data) const override;
 	void ReleaseElementData(Rml::DecoratorDataHandle element_data) const override;
 
 
 	/// Called to render the decorator on an element.
 	/// Called to render the decorator on an element.
-	/// @param element[in] The element to render the decorator on.
-	/// @param element_data[in] The handle to the data generated by the decorator for the element.
 	void RenderElement(Rml::Element* element, Rml::DecoratorDataHandle element_data) const override;
 	void RenderElement(Rml::Element* element, Rml::DecoratorDataHandle element_data) const override;
 
 
 private:
 private:

+ 1 - 1
Samples/invaders/src/DecoratorStarfield.cpp

@@ -55,7 +55,7 @@ bool DecoratorStarfield::Initialise(int _num_layers, const Rml::Colourb& _top_co
 	return true;
 	return true;
 }
 }
 
 
-Rml::DecoratorDataHandle DecoratorStarfield::GenerateElementData(Rml::Element* element) const
+Rml::DecoratorDataHandle DecoratorStarfield::GenerateElementData(Rml::Element* element, Rml::BoxArea /*paint_area*/) const
 {
 {
 	const double t = Rml::GetSystemInterface()->GetElapsedTime();
 	const double t = Rml::GetSystemInterface()->GetElapsedTime();
 
 

+ 1 - 6
Samples/invaders/src/DecoratorStarfield.h

@@ -40,16 +40,11 @@ public:
 		int top_density, int bottom_density);
 		int top_density, int bottom_density);
 
 
 	/// Called on a decorator to generate any required per-element data for a newly decorated element.
 	/// Called on a decorator to generate any required per-element data for a newly decorated element.
-	/// @param[in] element The newly decorated element.
-	/// @return A handle to a decorator-defined data handle, or nullptr if none is needed for the element.
-	Rml::DecoratorDataHandle GenerateElementData(Rml::Element* element) const override;
+	Rml::DecoratorDataHandle GenerateElementData(Rml::Element* element, Rml::BoxArea paint_area) const override;
 	/// Called to release element data generated by this decorator.
 	/// Called to release element data generated by this decorator.
-	/// @param[in] element_data The element data handle to release.
 	void ReleaseElementData(Rml::DecoratorDataHandle element_data) const override;
 	void ReleaseElementData(Rml::DecoratorDataHandle element_data) const override;
 
 
 	/// Called to render the decorator on an element.
 	/// Called to render the decorator on an element.
-	/// @param[in] element The element to render the decorator on.
-	/// @param[in] element_data The handle to the data generated by the decorator for the element.
 	void RenderElement(Rml::Element* element, Rml::DecoratorDataHandle element_data) const override;
 	void RenderElement(Rml::Element* element, Rml::DecoratorDataHandle element_data) const override;
 
 
 private:
 private:

+ 1 - 1
Samples/luainvaders/src/DecoratorDefender.cpp

@@ -49,7 +49,7 @@ bool DecoratorDefender::Initialise(const Rml::Texture& texture)
 	return true;
 	return true;
 }
 }
 
 
-Rml::DecoratorDataHandle DecoratorDefender::GenerateElementData(Rml::Element* /*element*/) const
+Rml::DecoratorDataHandle DecoratorDefender::GenerateElementData(Rml::Element* /*element*/, Rml::BoxArea /*paint_area*/) const
 {
 {
 	return Rml::Decorator::INVALID_DECORATORDATAHANDLE;
 	return Rml::Decorator::INVALID_DECORATORDATAHANDLE;
 }
 }

+ 1 - 6
Samples/luainvaders/src/DecoratorDefender.h

@@ -38,16 +38,11 @@ public:
 	bool Initialise(const Rml::Texture& texture);
 	bool Initialise(const Rml::Texture& texture);
 
 
 	/// Called on a decorator to generate any required per-element data for a newly decorated element.
 	/// Called on a decorator to generate any required per-element data for a newly decorated element.
-	/// @param element[in] The newly decorated element.
-	/// @return A handle to a decorator-defined data handle, or nullptr if none is needed for the element.
-	Rml::DecoratorDataHandle GenerateElementData(Rml::Element* element) const override;
+	Rml::DecoratorDataHandle GenerateElementData(Rml::Element* element, Rml::BoxArea paint_area) const override;
 	/// Called to release element data generated by this decorator.
 	/// Called to release element data generated by this decorator.
-	/// @param element_data[in] The element data handle to release.
 	void ReleaseElementData(Rml::DecoratorDataHandle element_data) const override;
 	void ReleaseElementData(Rml::DecoratorDataHandle element_data) const override;
 
 
 	/// Called to render the decorator on an element.
 	/// Called to render the decorator on an element.
-	/// @param element[in] The element to render the decorator on.
-	/// @param element_data[in] The handle to the data generated by the decorator for the element.
 	void RenderElement(Rml::Element* element, Rml::DecoratorDataHandle element_data) const override;
 	void RenderElement(Rml::Element* element, Rml::DecoratorDataHandle element_data) const override;
 
 
 private:
 private:

+ 1 - 1
Samples/luainvaders/src/DecoratorStarfield.cpp

@@ -55,7 +55,7 @@ bool DecoratorStarfield::Initialise(int _num_layers, const Rml::Colourb& _top_co
 	return true;
 	return true;
 }
 }
 
 
-Rml::DecoratorDataHandle DecoratorStarfield::GenerateElementData(Rml::Element* element) const
+Rml::DecoratorDataHandle DecoratorStarfield::GenerateElementData(Rml::Element* element, Rml::BoxArea /*paint_area*/) const
 {
 {
 	const double t = Rml::GetSystemInterface()->GetElapsedTime();
 	const double t = Rml::GetSystemInterface()->GetElapsedTime();
 
 

+ 1 - 6
Samples/luainvaders/src/DecoratorStarfield.h

@@ -40,16 +40,11 @@ public:
 		int top_density, int bottom_density);
 		int top_density, int bottom_density);
 
 
 	/// Called on a decorator to generate any required per-element data for a newly decorated element.
 	/// Called on a decorator to generate any required per-element data for a newly decorated element.
-	/// @param[in] element The newly decorated element.
-	/// @return A handle to a decorator-defined data handle, or nullptr if none is needed for the element.
-	Rml::DecoratorDataHandle GenerateElementData(Rml::Element* element) const override;
+	Rml::DecoratorDataHandle GenerateElementData(Rml::Element* element, Rml::BoxArea paint_area) const override;
 	/// Called to release element data generated by this decorator.
 	/// Called to release element data generated by this decorator.
-	/// @param[in] element_data The element data handle to release.
 	void ReleaseElementData(Rml::DecoratorDataHandle element_data) const override;
 	void ReleaseElementData(Rml::DecoratorDataHandle element_data) const override;
 
 
 	/// Called to render the decorator on an element.
 	/// Called to render the decorator on an element.
-	/// @param[in] element The element to render the decorator on.
-	/// @param[in] element_data The handle to the data generated by the decorator for the element.
 	void RenderElement(Rml::Element* element, Rml::DecoratorDataHandle element_data) const override;
 	void RenderElement(Rml::Element* element, Rml::DecoratorDataHandle element_data) const override;
 
 
 private:
 private:

+ 10 - 11
Source/Core/DecoratorGradient.cpp

@@ -160,7 +160,7 @@ bool DecoratorStraightGradient::Initialise(const Direction in_direction, const C
 	return true;
 	return true;
 }
 }
 
 
-DecoratorDataHandle DecoratorStraightGradient::GenerateElementData(Element* element) const
+DecoratorDataHandle DecoratorStraightGradient::GenerateElementData(Element* element, BoxArea paint_area) const
 {
 {
 	Geometry* geometry = new Geometry();
 	Geometry* geometry = new Geometry();
 	const Box& box = element->GetBox();
 	const Box& box = element->GetBox();
@@ -168,7 +168,7 @@ DecoratorDataHandle DecoratorStraightGradient::GenerateElementData(Element* elem
 	const ComputedValues& computed = element->GetComputedValues();
 	const ComputedValues& computed = element->GetComputedValues();
 	const float opacity = computed.opacity();
 	const float opacity = computed.opacity();
 
 
-	GeometryUtilities::GenerateBackground(geometry, element->GetBox(), Vector2f(0), computed.border_radius(), Colourb());
+	GeometryUtilities::GenerateBackground(geometry, element->GetBox(), Vector2f(0), computed.border_radius(), Colourb(), paint_area);
 
 
 	// Apply opacity
 	// Apply opacity
 	Colourb colour_start = start;
 	Colourb colour_start = start;
@@ -176,8 +176,8 @@ DecoratorDataHandle DecoratorStraightGradient::GenerateElementData(Element* elem
 	Colourb colour_stop = stop;
 	Colourb colour_stop = stop;
 	colour_stop.alpha = (byte)(opacity * (float)colour_stop.alpha);
 	colour_stop.alpha = (byte)(opacity * (float)colour_stop.alpha);
 
 
-	const Vector2f padding_offset = box.GetPosition(BoxArea::Padding);
-	const Vector2f padding_size = box.GetSize(BoxArea::Padding);
+	const Vector2f offset = box.GetPosition(paint_area);
+	const Vector2f size = box.GetSize(paint_area);
 
 
 	Vector<Vertex>& vertices = geometry->GetVertices();
 	Vector<Vertex>& vertices = geometry->GetVertices();
 
 
@@ -185,7 +185,7 @@ DecoratorDataHandle DecoratorStraightGradient::GenerateElementData(Element* elem
 	{
 	{
 		for (int i = 0; i < (int)vertices.size(); i++)
 		for (int i = 0; i < (int)vertices.size(); i++)
 		{
 		{
-			const float t = Math::Clamp((vertices[i].position.x - padding_offset.x) / padding_size.x, 0.0f, 1.0f);
+			const float t = Math::Clamp((vertices[i].position.x - offset.x) / size.x, 0.0f, 1.0f);
 			vertices[i].colour = Math::RoundedLerp(t, colour_start, colour_stop);
 			vertices[i].colour = Math::RoundedLerp(t, colour_start, colour_stop);
 		}
 		}
 	}
 	}
@@ -193,7 +193,7 @@ DecoratorDataHandle DecoratorStraightGradient::GenerateElementData(Element* elem
 	{
 	{
 		for (int i = 0; i < (int)vertices.size(); i++)
 		for (int i = 0; i < (int)vertices.size(); i++)
 		{
 		{
-			const float t = Math::Clamp((vertices[i].position.y - padding_offset.y) / padding_size.y, 0.0f, 1.0f);
+			const float t = Math::Clamp((vertices[i].position.y - offset.y) / size.y, 0.0f, 1.0f);
 			vertices[i].colour = Math::RoundedLerp(t, colour_start, colour_stop);
 			vertices[i].colour = Math::RoundedLerp(t, colour_start, colour_stop);
 		}
 		}
 	}
 	}
@@ -262,7 +262,7 @@ bool DecoratorLinearGradient::Initialise(bool in_repeating, Corner in_corner, fl
 	return !color_stops.empty();
 	return !color_stops.empty();
 }
 }
 
 
-DecoratorDataHandle DecoratorLinearGradient::GenerateElementData(Element* element) const
+DecoratorDataHandle DecoratorLinearGradient::GenerateElementData(Element* element, BoxArea paint_area) const
 {
 {
 	RenderInterface* render_interface = GetRenderInterface();
 	RenderInterface* render_interface = GetRenderInterface();
 	if (!render_interface)
 	if (!render_interface)
@@ -270,9 +270,8 @@ DecoratorDataHandle DecoratorLinearGradient::GenerateElementData(Element* elemen
 
 
 	RMLUI_ASSERT(!color_stops.empty());
 	RMLUI_ASSERT(!color_stops.empty());
 
 
-	BoxArea box_area = BoxArea::Padding;
 	const Box& box = element->GetBox();
 	const Box& box = element->GetBox();
-	const Vector2f dimensions = box.GetSize(box_area);
+	const Vector2f dimensions = box.GetSize(paint_area);
 
 
 	LinearGradientShape gradient_shape = CalculateShape(dimensions);
 	LinearGradientShape gradient_shape = CalculateShape(dimensions);
 
 
@@ -299,9 +298,9 @@ DecoratorDataHandle DecoratorLinearGradient::GenerateElementData(Element* elemen
 
 
 	const ComputedValues& computed = element->GetComputedValues();
 	const ComputedValues& computed = element->GetComputedValues();
 	const byte alpha = byte(computed.opacity() * 255.f);
 	const byte alpha = byte(computed.opacity() * 255.f);
-	GeometryUtilities::GenerateBackground(&geometry, box, Vector2f(), computed.border_radius(), Colourb(255, alpha), box_area);
+	GeometryUtilities::GenerateBackground(&geometry, box, Vector2f(), computed.border_radius(), Colourb(255, alpha), paint_area);
 
 
-	const Vector2f render_offset = box.GetPosition(box_area);
+	const Vector2f render_offset = box.GetPosition(paint_area);
 	for (Vertex& vertex : geometry.GetVertices())
 	for (Vertex& vertex : geometry.GetVertices())
 		vertex.tex_coord = vertex.position - render_offset;
 		vertex.tex_coord = vertex.position - render_offset;
 
 

+ 2 - 2
Source/Core/DecoratorGradient.h

@@ -52,7 +52,7 @@ public:
 
 
 	bool Initialise(Direction direction, Colourb start, Colourb stop);
 	bool Initialise(Direction direction, Colourb start, Colourb stop);
 
 
-	DecoratorDataHandle GenerateElementData(Element* element) const override;
+	DecoratorDataHandle GenerateElementData(Element* element, BoxArea paint_area) const override;
 	void ReleaseElementData(DecoratorDataHandle element_data) const override;
 	void ReleaseElementData(DecoratorDataHandle element_data) const override;
 
 
 	void RenderElement(Element* element, DecoratorDataHandle element_data) const override;
 	void RenderElement(Element* element, DecoratorDataHandle element_data) const override;
@@ -89,7 +89,7 @@ public:
 
 
 	bool Initialise(bool repeating, Corner corner, float angle, const ColorStopList& color_stops);
 	bool Initialise(bool repeating, Corner corner, float angle, const ColorStopList& color_stops);
 
 
-	DecoratorDataHandle GenerateElementData(Element* element) const override;
+	DecoratorDataHandle GenerateElementData(Element* element, BoxArea paint_area) const override;
 	void ReleaseElementData(DecoratorDataHandle element_data) const override;
 	void ReleaseElementData(DecoratorDataHandle element_data) const override;
 
 
 	void RenderElement(Element* element, DecoratorDataHandle element_data) const override;
 	void RenderElement(Element* element, DecoratorDataHandle element_data) const override;

+ 8 - 3
Source/Core/DecoratorNinePatch.cpp

@@ -54,7 +54,7 @@ bool DecoratorNinePatch::Initialise(const Rectanglef& _rect_outer, const Rectang
 	return (texture_index >= 0);
 	return (texture_index >= 0);
 }
 }
 
 
-DecoratorDataHandle DecoratorNinePatch::GenerateElementData(Element* element) const
+DecoratorDataHandle DecoratorNinePatch::GenerateElementData(Element* element, BoxArea paint_area) const
 {
 {
 	const auto& computed = element->GetComputedValues();
 	const auto& computed = element->GetComputedValues();
 
 
@@ -64,7 +64,8 @@ DecoratorDataHandle DecoratorNinePatch::GenerateElementData(Element* element) co
 	data->SetTexture(texture);
 	data->SetTexture(texture);
 	const Vector2f texture_dimensions(texture->GetDimensions());
 	const Vector2f texture_dimensions(texture->GetDimensions());
 
 
-	const Vector2f surface_dimensions = element->GetBox().GetSize(BoxArea::Padding).Round();
+	const Vector2f surface_offset = element->GetBox().GetPosition(paint_area);
+	const Vector2f surface_dimensions = element->GetBox().GetSize(paint_area).Round();
 
 
 	const float opacity = computed.opacity();
 	const float opacity = computed.opacity();
 	Colourb quad_colour = computed.image_color();
 	Colourb quad_colour = computed.image_color();
@@ -126,6 +127,10 @@ DecoratorDataHandle DecoratorNinePatch::GenerateElementData(Element* element) co
 		}
 		}
 	}
 	}
 
 
+	// Now offset all positions, relative to the border box.
+	for (Vector2f& surface_pos_entry : surface_pos)
+		surface_pos_entry += surface_offset;
+
 	// Round the inner corners
 	// Round the inner corners
 	surface_pos[1] = surface_pos[1].Round();
 	surface_pos[1] = surface_pos[1].Round();
 	surface_pos[2] = surface_pos[2].Round();
 	surface_pos[2] = surface_pos[2].Round();
@@ -176,7 +181,7 @@ void DecoratorNinePatch::ReleaseElementData(DecoratorDataHandle element_data) co
 void DecoratorNinePatch::RenderElement(Element* element, DecoratorDataHandle element_data) const
 void DecoratorNinePatch::RenderElement(Element* element, DecoratorDataHandle element_data) const
 {
 {
 	Geometry* data = reinterpret_cast<Geometry*>(element_data);
 	Geometry* data = reinterpret_cast<Geometry*>(element_data);
-	data->Render(element->GetAbsoluteOffset(BoxArea::Padding));
+	data->Render(element->GetAbsoluteOffset(BoxArea::Border));
 }
 }
 
 
 DecoratorNinePatchInstancer::DecoratorNinePatchInstancer()
 DecoratorNinePatchInstancer::DecoratorNinePatchInstancer()

+ 1 - 1
Source/Core/DecoratorNinePatch.h

@@ -43,7 +43,7 @@ public:
 	bool Initialise(const Rectanglef& rect_outer, const Rectanglef& rect_inner, const Array<NumericValue, 4>* _edges, const Texture& texture,
 	bool Initialise(const Rectanglef& rect_outer, const Rectanglef& rect_inner, const Array<NumericValue, 4>* _edges, const Texture& texture,
 		float display_scale);
 		float display_scale);
 
 
-	DecoratorDataHandle GenerateElementData(Element* element) const override;
+	DecoratorDataHandle GenerateElementData(Element* element, BoxArea paint_area) const override;
 	void ReleaseElementData(DecoratorDataHandle element_data) const override;
 	void ReleaseElementData(DecoratorDataHandle element_data) const override;
 
 
 	void RenderElement(Element* element, DecoratorDataHandle element_data) const override;
 	void RenderElement(Element* element, DecoratorDataHandle element_data) const override;

+ 32 - 29
Source/Core/DecoratorTiledBox.cpp

@@ -95,7 +95,7 @@ bool DecoratorTiledBox::Initialise(const Tile* _tiles, const Texture* _textures)
 	return true;
 	return true;
 }
 }
 
 
-DecoratorDataHandle DecoratorTiledBox::GenerateElementData(Element* element) const
+DecoratorDataHandle DecoratorTiledBox::GenerateElementData(Element* element, BoxArea paint_area) const
 {
 {
 	// Initialise the tiles for this element.
 	// Initialise the tiles for this element.
 	for (int i = 0; i < 9; i++)
 	for (int i = 0; i < 9; i++)
@@ -104,7 +104,8 @@ DecoratorDataHandle DecoratorTiledBox::GenerateElementData(Element* element) con
 		tiles[i].CalculateDimensions(*GetTexture(tiles[i].texture_index));
 		tiles[i].CalculateDimensions(*GetTexture(tiles[i].texture_index));
 	}
 	}
 
 
-	Vector2f padded_size = element->GetBox().GetSize(BoxArea::Padding);
+	const Vector2f offset = element->GetBox().GetPosition(paint_area);
+	const Vector2f size = element->GetBox().GetSize(paint_area);
 
 
 	// Calculate the natural dimensions of tile corners and edges.
 	// Calculate the natural dimensions of tile corners and edges.
 	const Vector2f natural_top_left = tiles[TOP_LEFT_CORNER].GetNaturalDimensions(element);
 	const Vector2f natural_top_left = tiles[TOP_LEFT_CORNER].GetNaturalDimensions(element);
@@ -132,60 +133,60 @@ DecoratorDataHandle DecoratorTiledBox::GenerateElementData(Element* element) con
 
 
 	// Scale the top corners down if appropriate. If they are scaled, then the left and right edges are also scaled
 	// Scale the top corners down if appropriate. If they are scaled, then the left and right edges are also scaled
 	// if they shared a width with their corner. Best solution? Don't know.
 	// if they shared a width with their corner. Best solution? Don't know.
-	if (padded_size.x < top_left.x + top_right.x)
+	if (size.x < top_left.x + top_right.x)
 	{
 	{
 		float minimum_width = top_left.x + top_right.x;
 		float minimum_width = top_left.x + top_right.x;
 
 
-		top_left.x = padded_size.x * (top_left.x / minimum_width);
+		top_left.x = size.x * (top_left.x / minimum_width);
 		if (natural_top_left.x == natural_left.x)
 		if (natural_top_left.x == natural_left.x)
 			left.x = top_left.x;
 			left.x = top_left.x;
 
 
-		top_right.x = padded_size.x * (top_right.x / minimum_width);
+		top_right.x = size.x * (top_right.x / minimum_width);
 		if (natural_top_right.x == natural_right.x)
 		if (natural_top_right.x == natural_right.x)
 			right.x = top_right.x;
 			right.x = top_right.x;
 	}
 	}
 
 
 	// Scale the bottom corners down if appropriate. If they are scaled, then the left and right edges are also scaled
 	// Scale the bottom corners down if appropriate. If they are scaled, then the left and right edges are also scaled
 	// if they shared a width with their corner. Best solution? Don't know.
 	// if they shared a width with their corner. Best solution? Don't know.
-	if (padded_size.x < bottom_left.x + bottom_right.x)
+	if (size.x < bottom_left.x + bottom_right.x)
 	{
 	{
 		float minimum_width = bottom_left.x + bottom_right.x;
 		float minimum_width = bottom_left.x + bottom_right.x;
 
 
-		bottom_left.x = padded_size.x * (bottom_left.x / minimum_width);
+		bottom_left.x = size.x * (bottom_left.x / minimum_width);
 		if (natural_bottom_left.x == natural_left.x)
 		if (natural_bottom_left.x == natural_left.x)
 			left.x = bottom_left.x;
 			left.x = bottom_left.x;
 
 
-		bottom_right.x = padded_size.x * (bottom_right.x / minimum_width);
+		bottom_right.x = size.x * (bottom_right.x / minimum_width);
 		if (natural_bottom_right.x == natural_right.x)
 		if (natural_bottom_right.x == natural_right.x)
 			right.x = bottom_right.x;
 			right.x = bottom_right.x;
 	}
 	}
 
 
 	// Scale the left corners down if appropriate. If they are scaled, then the top and bottom edges are also scaled
 	// Scale the left corners down if appropriate. If they are scaled, then the top and bottom edges are also scaled
 	// if they shared a width with their corner. Best solution? Don't know.
 	// if they shared a width with their corner. Best solution? Don't know.
-	if (padded_size.y < top_left.y + bottom_left.y)
+	if (size.y < top_left.y + bottom_left.y)
 	{
 	{
 		float minimum_height = top_left.y + bottom_left.y;
 		float minimum_height = top_left.y + bottom_left.y;
 
 
-		top_left.y = padded_size.y * (top_left.y / minimum_height);
+		top_left.y = size.y * (top_left.y / minimum_height);
 		if (natural_top_left.y == natural_top.y)
 		if (natural_top_left.y == natural_top.y)
 			top.y = top_left.y;
 			top.y = top_left.y;
 
 
-		bottom_left.y = padded_size.y * (bottom_left.y / minimum_height);
+		bottom_left.y = size.y * (bottom_left.y / minimum_height);
 		if (natural_bottom_left.y == natural_bottom.y)
 		if (natural_bottom_left.y == natural_bottom.y)
 			bottom.y = bottom_left.y;
 			bottom.y = bottom_left.y;
 	}
 	}
 
 
 	// Scale the right corners down if appropriate. If they are scaled, then the top and bottom edges are also scaled
 	// Scale the right corners down if appropriate. If they are scaled, then the top and bottom edges are also scaled
 	// if they shared a width with their corner. Best solution? Don't know.
 	// if they shared a width with their corner. Best solution? Don't know.
-	if (padded_size.y < top_right.y + bottom_right.y)
+	if (size.y < top_right.y + bottom_right.y)
 	{
 	{
 		float minimum_height = top_right.y + bottom_right.y;
 		float minimum_height = top_right.y + bottom_right.y;
 
 
-		top_right.y = padded_size.y * (top_right.y / minimum_height);
+		top_right.y = size.y * (top_right.y / minimum_height);
 		if (natural_top_right.y == natural_top.y)
 		if (natural_top_right.y == natural_top.y)
 			top.y = top_right.y;
 			top.y = top_right.y;
 
 
-		bottom_right.y = padded_size.y * (bottom_right.y / minimum_height);
+		bottom_right.y = size.y * (bottom_right.y / minimum_height);
 		if (natural_bottom_right.y == natural_bottom.y)
 		if (natural_bottom_right.y == natural_bottom.y)
 			bottom.y = bottom_right.y;
 			bottom.y = bottom_right.y;
 	}
 	}
@@ -196,44 +197,46 @@ DecoratorDataHandle DecoratorTiledBox::GenerateElementData(Element* element) con
 
 
 	// Generate the geometry for the top-left tile.
 	// Generate the geometry for the top-left tile.
 	tiles[TOP_LEFT_CORNER].GenerateGeometry(data->geometry[tiles[TOP_LEFT_CORNER].texture_index].GetVertices(),
 	tiles[TOP_LEFT_CORNER].GenerateGeometry(data->geometry[tiles[TOP_LEFT_CORNER].texture_index].GetVertices(),
-		data->geometry[tiles[TOP_LEFT_CORNER].texture_index].GetIndices(), computed, Vector2f(0, 0), top_left, top_left);
+		data->geometry[tiles[TOP_LEFT_CORNER].texture_index].GetIndices(), computed, offset, top_left, top_left);
 	// Generate the geometry for the top edge tiles.
 	// Generate the geometry for the top edge tiles.
 	tiles[TOP_EDGE].GenerateGeometry(data->geometry[tiles[TOP_EDGE].texture_index].GetVertices(),
 	tiles[TOP_EDGE].GenerateGeometry(data->geometry[tiles[TOP_EDGE].texture_index].GetVertices(),
-		data->geometry[tiles[TOP_EDGE].texture_index].GetIndices(), computed, Vector2f(top_left.x, 0),
-		Vector2f(padded_size.x - (top_left.x + top_right.x), top.y), top);
+		data->geometry[tiles[TOP_EDGE].texture_index].GetIndices(), computed, offset + Vector2f(top_left.x, 0),
+		Vector2f(size.x - (top_left.x + top_right.x), top.y), top);
 	// Generate the geometry for the top-right tile.
 	// Generate the geometry for the top-right tile.
 	tiles[TOP_RIGHT_CORNER].GenerateGeometry(data->geometry[tiles[TOP_RIGHT_CORNER].texture_index].GetVertices(),
 	tiles[TOP_RIGHT_CORNER].GenerateGeometry(data->geometry[tiles[TOP_RIGHT_CORNER].texture_index].GetVertices(),
-		data->geometry[tiles[TOP_RIGHT_CORNER].texture_index].GetIndices(), computed, Vector2f(padded_size.x - top_right.x, 0), top_right, top_right);
+		data->geometry[tiles[TOP_RIGHT_CORNER].texture_index].GetIndices(), computed, offset + Vector2f(size.x - top_right.x, 0), top_right,
+		top_right);
 
 
 	// Generate the geometry for the left side.
 	// Generate the geometry for the left side.
 	tiles[LEFT_EDGE].GenerateGeometry(data->geometry[tiles[LEFT_EDGE].texture_index].GetVertices(),
 	tiles[LEFT_EDGE].GenerateGeometry(data->geometry[tiles[LEFT_EDGE].texture_index].GetVertices(),
-		data->geometry[tiles[LEFT_EDGE].texture_index].GetIndices(), computed, Vector2f(0, top_left.y),
-		Vector2f(left.x, padded_size.y - (top_left.y + bottom_left.y)), left);
+		data->geometry[tiles[LEFT_EDGE].texture_index].GetIndices(), computed, offset + Vector2f(0, top_left.y),
+		Vector2f(left.x, size.y - (top_left.y + bottom_left.y)), left);
 
 
 	// Generate the geometry for the right side.
 	// Generate the geometry for the right side.
 	tiles[RIGHT_EDGE].GenerateGeometry(data->geometry[tiles[RIGHT_EDGE].texture_index].GetVertices(),
 	tiles[RIGHT_EDGE].GenerateGeometry(data->geometry[tiles[RIGHT_EDGE].texture_index].GetVertices(),
-		data->geometry[tiles[RIGHT_EDGE].texture_index].GetIndices(), computed, Vector2f((padded_size.x - right.x), top_right.y),
-		Vector2f(right.x, padded_size.y - (top_right.y + bottom_right.y)), right);
+		data->geometry[tiles[RIGHT_EDGE].texture_index].GetIndices(), computed, offset + Vector2f((size.x - right.x), top_right.y),
+		Vector2f(right.x, size.y - (top_right.y + bottom_right.y)), right);
 
 
 	// Generate the geometry for the bottom-left tile.
 	// Generate the geometry for the bottom-left tile.
 	tiles[BOTTOM_LEFT_CORNER].GenerateGeometry(data->geometry[tiles[BOTTOM_LEFT_CORNER].texture_index].GetVertices(),
 	tiles[BOTTOM_LEFT_CORNER].GenerateGeometry(data->geometry[tiles[BOTTOM_LEFT_CORNER].texture_index].GetVertices(),
-		data->geometry[tiles[BOTTOM_LEFT_CORNER].texture_index].GetIndices(), computed, Vector2f(0, padded_size.y - bottom_left.y), bottom_left,
+		data->geometry[tiles[BOTTOM_LEFT_CORNER].texture_index].GetIndices(), computed, offset + Vector2f(0, size.y - bottom_left.y), bottom_left,
 		bottom_left);
 		bottom_left);
 	// Generate the geometry for the bottom edge tiles.
 	// Generate the geometry for the bottom edge tiles.
 	tiles[BOTTOM_EDGE].GenerateGeometry(data->geometry[tiles[BOTTOM_EDGE].texture_index].GetVertices(),
 	tiles[BOTTOM_EDGE].GenerateGeometry(data->geometry[tiles[BOTTOM_EDGE].texture_index].GetVertices(),
-		data->geometry[tiles[BOTTOM_EDGE].texture_index].GetIndices(), computed, Vector2f(bottom_left.x, padded_size.y - bottom.y),
-		Vector2f(padded_size.x - (bottom_left.x + bottom_right.x), bottom.y), bottom);
+		data->geometry[tiles[BOTTOM_EDGE].texture_index].GetIndices(), computed, offset + Vector2f(bottom_left.x, size.y - bottom.y),
+		Vector2f(size.x - (bottom_left.x + bottom_right.x), bottom.y), bottom);
 	// Generate the geometry for the bottom-right tile.
 	// Generate the geometry for the bottom-right tile.
 	tiles[BOTTOM_RIGHT_CORNER].GenerateGeometry(data->geometry[tiles[BOTTOM_RIGHT_CORNER].texture_index].GetVertices(),
 	tiles[BOTTOM_RIGHT_CORNER].GenerateGeometry(data->geometry[tiles[BOTTOM_RIGHT_CORNER].texture_index].GetVertices(),
 		data->geometry[tiles[BOTTOM_RIGHT_CORNER].texture_index].GetIndices(), computed,
 		data->geometry[tiles[BOTTOM_RIGHT_CORNER].texture_index].GetIndices(), computed,
-		Vector2f(padded_size.x - bottom_right.x, padded_size.y - bottom_right.y), bottom_right, bottom_right);
+		offset + Vector2f(size.x - bottom_right.x, size.y - bottom_right.y), bottom_right, bottom_right);
 
 
 	// Generate the centre geometry.
 	// Generate the centre geometry.
 	Vector2f centre_dimensions = tiles[CENTRE].GetNaturalDimensions(element);
 	Vector2f centre_dimensions = tiles[CENTRE].GetNaturalDimensions(element);
-	Vector2f centre_surface_dimensions(padded_size.x - (left.x + right.x), padded_size.y - (top.y + bottom.y));
+	Vector2f centre_surface_dimensions(size.x - (left.x + right.x), size.y - (top.y + bottom.y));
 
 
 	tiles[CENTRE].GenerateGeometry(data->geometry[tiles[CENTRE].texture_index].GetVertices(),
 	tiles[CENTRE].GenerateGeometry(data->geometry[tiles[CENTRE].texture_index].GetVertices(),
-		data->geometry[tiles[CENTRE].texture_index].GetIndices(), computed, Vector2f(left.x, top.y), centre_surface_dimensions, centre_dimensions);
+		data->geometry[tiles[CENTRE].texture_index].GetIndices(), computed, offset + Vector2f(left.x, top.y), centre_surface_dimensions,
+		centre_dimensions);
 
 
 	// Set the textures on the geometry.
 	// Set the textures on the geometry.
 	const Texture* texture = nullptr;
 	const Texture* texture = nullptr;
@@ -251,7 +254,7 @@ void DecoratorTiledBox::ReleaseElementData(DecoratorDataHandle element_data) con
 
 
 void DecoratorTiledBox::RenderElement(Element* element, DecoratorDataHandle element_data) const
 void DecoratorTiledBox::RenderElement(Element* element, DecoratorDataHandle element_data) const
 {
 {
-	Vector2f translation = element->GetAbsoluteOffset(BoxArea::Padding).Round();
+	Vector2f translation = element->GetAbsoluteOffset(BoxArea::Border);
 	DecoratorTiledBoxData* data = reinterpret_cast<DecoratorTiledBoxData*>(element_data);
 	DecoratorTiledBoxData* data = reinterpret_cast<DecoratorTiledBoxData*>(element_data);
 
 
 	for (int i = 0; i < data->num_textures; i++)
 	for (int i = 0; i < data->num_textures; i++)

+ 1 - 1
Source/Core/DecoratorTiledBox.h

@@ -49,7 +49,7 @@ public:
 	bool Initialise(const Tile* tiles, const Texture* textures);
 	bool Initialise(const Tile* tiles, const Texture* textures);
 
 
 	/// Called on a decorator to generate any required per-element data for a newly decorated element.
 	/// Called on a decorator to generate any required per-element data for a newly decorated element.
-	DecoratorDataHandle GenerateElementData(Element* element) const override;
+	DecoratorDataHandle GenerateElementData(Element* element, BoxArea paint_area) const override;
 	/// Called to release element data generated by this decorator.
 	/// Called to release element data generated by this decorator.
 	void ReleaseElementData(DecoratorDataHandle element_data) const override;
 	void ReleaseElementData(DecoratorDataHandle element_data) const override;
 
 

+ 14 - 13
Source/Core/DecoratorTiledHorizontal.cpp

@@ -75,7 +75,7 @@ bool DecoratorTiledHorizontal::Initialise(const Tile* _tiles, const Texture* _te
 	return true;
 	return true;
 }
 }
 
 
-DecoratorDataHandle DecoratorTiledHorizontal::GenerateElementData(Element* element) const
+DecoratorDataHandle DecoratorTiledHorizontal::GenerateElementData(Element* element, BoxArea paint_area) const
 {
 {
 	// Initialise the tiles for this element.
 	// Initialise the tiles for this element.
 	for (int i = 0; i < 3; i++)
 	for (int i = 0; i < 3; i++)
@@ -84,41 +84,42 @@ DecoratorDataHandle DecoratorTiledHorizontal::GenerateElementData(Element* eleme
 	const int num_textures = GetNumTextures();
 	const int num_textures = GetNumTextures();
 	DecoratorTiledHorizontalData* data = new DecoratorTiledHorizontalData(num_textures);
 	DecoratorTiledHorizontalData* data = new DecoratorTiledHorizontalData(num_textures);
 
 
-	Vector2f padded_size = element->GetBox().GetSize(BoxArea::Padding);
+	const Vector2f offset = element->GetBox().GetPosition(paint_area);
+	const Vector2f size = element->GetBox().GetSize(paint_area);
 
 
 	Vector2f left_dimensions = tiles[LEFT].GetNaturalDimensions(element);
 	Vector2f left_dimensions = tiles[LEFT].GetNaturalDimensions(element);
 	Vector2f right_dimensions = tiles[RIGHT].GetNaturalDimensions(element);
 	Vector2f right_dimensions = tiles[RIGHT].GetNaturalDimensions(element);
 	Vector2f centre_dimensions = tiles[CENTRE].GetNaturalDimensions(element);
 	Vector2f centre_dimensions = tiles[CENTRE].GetNaturalDimensions(element);
 
 
 	// Scale the tile sizes by the height scale.
 	// Scale the tile sizes by the height scale.
-	ScaleTileDimensions(left_dimensions, padded_size.y, Axis::Vertical);
-	ScaleTileDimensions(right_dimensions, padded_size.y, Axis::Vertical);
-	ScaleTileDimensions(centre_dimensions, padded_size.y, Axis::Vertical);
+	ScaleTileDimensions(left_dimensions, size.y, Axis::Vertical);
+	ScaleTileDimensions(right_dimensions, size.y, Axis::Vertical);
+	ScaleTileDimensions(centre_dimensions, size.y, Axis::Vertical);
 
 
 	// Round the outer tile widths now so that we don't get gaps when rounding again in GenerateGeometry.
 	// Round the outer tile widths now so that we don't get gaps when rounding again in GenerateGeometry.
 	left_dimensions.x = Math::Round(left_dimensions.x);
 	left_dimensions.x = Math::Round(left_dimensions.x);
 	right_dimensions.x = Math::Round(right_dimensions.x);
 	right_dimensions.x = Math::Round(right_dimensions.x);
 
 
 	// Shrink the x-sizes on the left and right tiles if necessary.
 	// Shrink the x-sizes on the left and right tiles if necessary.
-	if (padded_size.x < left_dimensions.x + right_dimensions.x)
+	if (size.x < left_dimensions.x + right_dimensions.x)
 	{
 	{
 		float minimum_width = left_dimensions.x + right_dimensions.x;
 		float minimum_width = left_dimensions.x + right_dimensions.x;
-		left_dimensions.x = padded_size.x * (left_dimensions.x / minimum_width);
-		right_dimensions.x = padded_size.x * (right_dimensions.x / minimum_width);
+		left_dimensions.x = size.x * (left_dimensions.x / minimum_width);
+		right_dimensions.x = size.x * (right_dimensions.x / minimum_width);
 	}
 	}
 
 
 	const ComputedValues& computed = element->GetComputedValues();
 	const ComputedValues& computed = element->GetComputedValues();
 
 
 	// Generate the geometry for the left tile.
 	// Generate the geometry for the left tile.
 	tiles[LEFT].GenerateGeometry(data->geometry[tiles[LEFT].texture_index].GetVertices(), data->geometry[tiles[LEFT].texture_index].GetIndices(),
 	tiles[LEFT].GenerateGeometry(data->geometry[tiles[LEFT].texture_index].GetVertices(), data->geometry[tiles[LEFT].texture_index].GetIndices(),
-		computed, Vector2f(0, 0), left_dimensions, left_dimensions);
+		computed, offset, left_dimensions, left_dimensions);
 	// Generate the geometry for the centre tiles.
 	// Generate the geometry for the centre tiles.
 	tiles[CENTRE].GenerateGeometry(data->geometry[tiles[CENTRE].texture_index].GetVertices(),
 	tiles[CENTRE].GenerateGeometry(data->geometry[tiles[CENTRE].texture_index].GetVertices(),
-		data->geometry[tiles[CENTRE].texture_index].GetIndices(), computed, Vector2f(left_dimensions.x, 0),
-		Vector2f(padded_size.x - (left_dimensions.x + right_dimensions.x), centre_dimensions.y), centre_dimensions);
+		data->geometry[tiles[CENTRE].texture_index].GetIndices(), computed, offset + Vector2f(left_dimensions.x, 0),
+		Vector2f(size.x - (left_dimensions.x + right_dimensions.x), centre_dimensions.y), centre_dimensions);
 	// Generate the geometry for the right tile.
 	// Generate the geometry for the right tile.
 	tiles[RIGHT].GenerateGeometry(data->geometry[tiles[RIGHT].texture_index].GetVertices(), data->geometry[tiles[RIGHT].texture_index].GetIndices(),
 	tiles[RIGHT].GenerateGeometry(data->geometry[tiles[RIGHT].texture_index].GetVertices(), data->geometry[tiles[RIGHT].texture_index].GetIndices(),
-		computed, Vector2f(padded_size.x - right_dimensions.x, 0), right_dimensions, right_dimensions);
+		computed, offset + Vector2f(size.x - right_dimensions.x, 0), right_dimensions, right_dimensions);
 
 
 	// Set the textures on the geometry.
 	// Set the textures on the geometry.
 	const Texture* texture = nullptr;
 	const Texture* texture = nullptr;
@@ -136,7 +137,7 @@ void DecoratorTiledHorizontal::ReleaseElementData(DecoratorDataHandle element_da
 
 
 void DecoratorTiledHorizontal::RenderElement(Element* element, DecoratorDataHandle element_data) const
 void DecoratorTiledHorizontal::RenderElement(Element* element, DecoratorDataHandle element_data) const
 {
 {
-	Vector2f translation = element->GetAbsoluteOffset(BoxArea::Padding).Round();
+	Vector2f translation = element->GetAbsoluteOffset(BoxArea::Border);
 	DecoratorTiledHorizontalData* data = reinterpret_cast<DecoratorTiledHorizontalData*>(element_data);
 	DecoratorTiledHorizontalData* data = reinterpret_cast<DecoratorTiledHorizontalData*>(element_data);
 
 
 	for (int i = 0; i < data->num_textures; i++)
 	for (int i = 0; i < data->num_textures; i++)

+ 1 - 1
Source/Core/DecoratorTiledHorizontal.h

@@ -49,7 +49,7 @@ public:
 	bool Initialise(const Tile* tiles, const Texture* textures);
 	bool Initialise(const Tile* tiles, const Texture* textures);
 
 
 	/// Called on a decorator to generate any required per-element data for a newly decorated element.
 	/// Called on a decorator to generate any required per-element data for a newly decorated element.
-	DecoratorDataHandle GenerateElementData(Element* element) const override;
+	DecoratorDataHandle GenerateElementData(Element* element, BoxArea paint_area) const override;
 	/// Called to release element data generated by this decorator.
 	/// Called to release element data generated by this decorator.
 	void ReleaseElementData(DecoratorDataHandle element_data) const override;
 	void ReleaseElementData(DecoratorDataHandle element_data) const override;
 
 

+ 6 - 4
Source/Core/DecoratorTiledImage.cpp

@@ -44,7 +44,7 @@ bool DecoratorTiledImage::Initialise(const Tile& _tile, const Texture& _texture)
 	return (tile.texture_index >= 0);
 	return (tile.texture_index >= 0);
 }
 }
 
 
-DecoratorDataHandle DecoratorTiledImage::GenerateElementData(Element* element) const
+DecoratorDataHandle DecoratorTiledImage::GenerateElementData(Element* element, BoxArea paint_area) const
 {
 {
 	// Calculate the tile's dimensions for this element.
 	// Calculate the tile's dimensions for this element.
 	tile.CalculateDimensions(*GetTexture(tile.texture_index));
 	tile.CalculateDimensions(*GetTexture(tile.texture_index));
@@ -54,9 +54,11 @@ DecoratorDataHandle DecoratorTiledImage::GenerateElementData(Element* element) c
 
 
 	const ComputedValues& computed = element->GetComputedValues();
 	const ComputedValues& computed = element->GetComputedValues();
 
 
+	const Vector2f offset = element->GetBox().GetPosition(paint_area);
+	const Vector2f size = element->GetBox().GetSize(paint_area);
+
 	// Generate the geometry for the tile.
 	// Generate the geometry for the tile.
-	tile.GenerateGeometry(data->GetVertices(), data->GetIndices(), computed, Vector2f(0, 0), element->GetBox().GetSize(BoxArea::Padding),
-		tile.GetNaturalDimensions(element));
+	tile.GenerateGeometry(data->GetVertices(), data->GetIndices(), computed, offset, size, tile.GetNaturalDimensions(element));
 
 
 	return reinterpret_cast<DecoratorDataHandle>(data);
 	return reinterpret_cast<DecoratorDataHandle>(data);
 }
 }
@@ -69,7 +71,7 @@ void DecoratorTiledImage::ReleaseElementData(DecoratorDataHandle element_data) c
 void DecoratorTiledImage::RenderElement(Element* element, DecoratorDataHandle element_data) const
 void DecoratorTiledImage::RenderElement(Element* element, DecoratorDataHandle element_data) const
 {
 {
 	Geometry* data = reinterpret_cast<Geometry*>(element_data);
 	Geometry* data = reinterpret_cast<Geometry*>(element_data);
-	data->Render(element->GetAbsoluteOffset(BoxArea::Padding).Round());
+	data->Render(element->GetAbsoluteOffset(BoxArea::Border));
 }
 }
 
 
 DecoratorTiledImageInstancer::DecoratorTiledImageInstancer() : DecoratorTiledInstancer(1)
 DecoratorTiledImageInstancer::DecoratorTiledImageInstancer() : DecoratorTiledInstancer(1)

+ 1 - 1
Source/Core/DecoratorTiledImage.h

@@ -49,7 +49,7 @@ public:
 	bool Initialise(const Tile& tile, const Texture& texture);
 	bool Initialise(const Tile& tile, const Texture& texture);
 
 
 	/// Called on a decorator to generate any required per-element data for a newly decorated element.
 	/// Called on a decorator to generate any required per-element data for a newly decorated element.
-	DecoratorDataHandle GenerateElementData(Element* element) const override;
+	DecoratorDataHandle GenerateElementData(Element* element, BoxArea paint_area) const override;
 	/// Called to release element data generated by this decorator.
 	/// Called to release element data generated by this decorator.
 	void ReleaseElementData(DecoratorDataHandle element_data) const override;
 	void ReleaseElementData(DecoratorDataHandle element_data) const override;
 
 

+ 13 - 12
Source/Core/DecoratorTiledVertical.cpp

@@ -76,7 +76,7 @@ bool DecoratorTiledVertical::Initialise(const Tile* _tiles, const Texture* _text
 	return true;
 	return true;
 }
 }
 
 
-DecoratorDataHandle DecoratorTiledVertical::GenerateElementData(Element* element) const
+DecoratorDataHandle DecoratorTiledVertical::GenerateElementData(Element* element, BoxArea paint_area) const
 {
 {
 	// Initialise the tile for this element.
 	// Initialise the tile for this element.
 	for (int i = 0; i < 3; i++)
 	for (int i = 0; i < 3; i++)
@@ -85,41 +85,42 @@ DecoratorDataHandle DecoratorTiledVertical::GenerateElementData(Element* element
 	const int num_textures = GetNumTextures();
 	const int num_textures = GetNumTextures();
 	DecoratorTiledVerticalData* data = new DecoratorTiledVerticalData(num_textures);
 	DecoratorTiledVerticalData* data = new DecoratorTiledVerticalData(num_textures);
 
 
-	Vector2f padded_size = element->GetBox().GetSize(BoxArea::Padding);
+	const Vector2f offset = element->GetBox().GetPosition(paint_area);
+	const Vector2f size = element->GetBox().GetSize(paint_area);
 
 
 	Vector2f top_dimensions = tiles[TOP].GetNaturalDimensions(element);
 	Vector2f top_dimensions = tiles[TOP].GetNaturalDimensions(element);
 	Vector2f bottom_dimensions = tiles[BOTTOM].GetNaturalDimensions(element);
 	Vector2f bottom_dimensions = tiles[BOTTOM].GetNaturalDimensions(element);
 	Vector2f centre_dimensions = tiles[CENTRE].GetNaturalDimensions(element);
 	Vector2f centre_dimensions = tiles[CENTRE].GetNaturalDimensions(element);
 
 
 	// Scale the tile sizes by the width scale.
 	// Scale the tile sizes by the width scale.
-	ScaleTileDimensions(top_dimensions, padded_size.x, Axis::Horizontal);
-	ScaleTileDimensions(bottom_dimensions, padded_size.x, Axis::Horizontal);
-	ScaleTileDimensions(centre_dimensions, padded_size.x, Axis::Horizontal);
+	ScaleTileDimensions(top_dimensions, size.x, Axis::Horizontal);
+	ScaleTileDimensions(bottom_dimensions, size.x, Axis::Horizontal);
+	ScaleTileDimensions(centre_dimensions, size.x, Axis::Horizontal);
 
 
 	// Round the outer tile heights now so that we don't get gaps when rounding again in GenerateGeometry.
 	// Round the outer tile heights now so that we don't get gaps when rounding again in GenerateGeometry.
 	top_dimensions.y = Math::Round(top_dimensions.y);
 	top_dimensions.y = Math::Round(top_dimensions.y);
 	bottom_dimensions.y = Math::Round(bottom_dimensions.y);
 	bottom_dimensions.y = Math::Round(bottom_dimensions.y);
 
 
 	// Shrink the y-sizes on the left and right tiles if necessary.
 	// Shrink the y-sizes on the left and right tiles if necessary.
-	if (padded_size.y < top_dimensions.y + bottom_dimensions.y)
+	if (size.y < top_dimensions.y + bottom_dimensions.y)
 	{
 	{
 		float minimum_height = top_dimensions.y + bottom_dimensions.y;
 		float minimum_height = top_dimensions.y + bottom_dimensions.y;
-		top_dimensions.y = padded_size.y * (top_dimensions.y / minimum_height);
-		bottom_dimensions.y = padded_size.y * (bottom_dimensions.y / minimum_height);
+		top_dimensions.y = size.y * (top_dimensions.y / minimum_height);
+		bottom_dimensions.y = size.y * (bottom_dimensions.y / minimum_height);
 	}
 	}
 
 
 	const ComputedValues& computed = element->GetComputedValues();
 	const ComputedValues& computed = element->GetComputedValues();
 
 
 	// Generate the geometry for the left tile.
 	// Generate the geometry for the left tile.
 	tiles[TOP].GenerateGeometry(data->geometry[tiles[TOP].texture_index].GetVertices(), data->geometry[tiles[TOP].texture_index].GetIndices(),
 	tiles[TOP].GenerateGeometry(data->geometry[tiles[TOP].texture_index].GetVertices(), data->geometry[tiles[TOP].texture_index].GetIndices(),
-		computed, Vector2f(0, 0), top_dimensions, top_dimensions);
+		computed, offset, top_dimensions, top_dimensions);
 	// Generate the geometry for the centre tiles.
 	// Generate the geometry for the centre tiles.
 	tiles[CENTRE].GenerateGeometry(data->geometry[tiles[CENTRE].texture_index].GetVertices(),
 	tiles[CENTRE].GenerateGeometry(data->geometry[tiles[CENTRE].texture_index].GetVertices(),
-		data->geometry[tiles[CENTRE].texture_index].GetIndices(), computed, Vector2f(0, top_dimensions.y),
-		Vector2f(centre_dimensions.x, padded_size.y - (top_dimensions.y + bottom_dimensions.y)), centre_dimensions);
+		data->geometry[tiles[CENTRE].texture_index].GetIndices(), computed, offset + Vector2f(0, top_dimensions.y),
+		Vector2f(centre_dimensions.x, size.y - (top_dimensions.y + bottom_dimensions.y)), centre_dimensions);
 	// Generate the geometry for the right tile.
 	// Generate the geometry for the right tile.
 	tiles[BOTTOM].GenerateGeometry(data->geometry[tiles[BOTTOM].texture_index].GetVertices(),
 	tiles[BOTTOM].GenerateGeometry(data->geometry[tiles[BOTTOM].texture_index].GetVertices(),
-		data->geometry[tiles[BOTTOM].texture_index].GetIndices(), computed, Vector2f(0, padded_size.y - bottom_dimensions.y), bottom_dimensions,
+		data->geometry[tiles[BOTTOM].texture_index].GetIndices(), computed, offset + Vector2f(0, size.y - bottom_dimensions.y), bottom_dimensions,
 		bottom_dimensions);
 		bottom_dimensions);
 
 
 	// Set the textures on the geometry.
 	// Set the textures on the geometry.

+ 1 - 1
Source/Core/DecoratorTiledVertical.h

@@ -49,7 +49,7 @@ public:
 	bool Initialise(const Tile* tiles, const Texture* textures);
 	bool Initialise(const Tile* tiles, const Texture* textures);
 
 
 	/// Called on a decorator to generate any required per-element data for a newly decorated element.
 	/// Called on a decorator to generate any required per-element data for a newly decorated element.
-	DecoratorDataHandle GenerateElementData(Element* element) const override;
+	DecoratorDataHandle GenerateElementData(Element* element, BoxArea paint_area) const override;
 	/// Called to release element data generated by this decorator.
 	/// Called to release element data generated by this decorator.
 	void ReleaseElementData(DecoratorDataHandle element_data) const override;
 	void ReleaseElementData(DecoratorDataHandle element_data) const override;
 
 

+ 5 - 4
Source/Core/ElementAnimation.cpp

@@ -171,7 +171,7 @@ static Property InterpolateProperties(const Property& p0, const Property& p1, fl
 
 
 	struct DecoratorDeclarationView {
 	struct DecoratorDeclarationView {
 		DecoratorDeclarationView(const DecoratorDeclaration& declaration) :
 		DecoratorDeclarationView(const DecoratorDeclaration& declaration) :
-			type(declaration.type), instancer(declaration.instancer), properties(declaration.properties)
+			type(declaration.type), instancer(declaration.instancer), properties(declaration.properties), paint_area(declaration.paint_area)
 		{}
 		{}
 		DecoratorDeclarationView(const NamedDecorator* specification) :
 		DecoratorDeclarationView(const NamedDecorator* specification) :
 			type(specification->type), instancer(Factory::GetDecoratorInstancer(specification->type)), properties(specification->properties)
 			type(specification->type), instancer(Factory::GetDecoratorInstancer(specification->type)), properties(specification->properties)
@@ -179,6 +179,7 @@ static Property InterpolateProperties(const Property& p0, const Property& p1, fl
 		const String& type;
 		const String& type;
 		DecoratorInstancer* instancer;
 		DecoratorInstancer* instancer;
 		const PropertyDictionary& properties;
 		const PropertyDictionary& properties;
+		BoxArea paint_area = BoxArea::Auto;
 	};
 	};
 
 
 	if (p0.unit == Unit::DECORATOR && p1.unit == Unit::DECORATOR)
 	if (p0.unit == Unit::DECORATOR && p1.unit == Unit::DECORATOR)
@@ -230,13 +231,13 @@ static Property InterpolateProperties(const Property& p0, const Property& p1, fl
 				return DiscreteInterpolation();
 				return DiscreteInterpolation();
 
 
 			if (d0_view.instancer != d1_view.instancer || d0_view.type != d1_view.type ||
 			if (d0_view.instancer != d1_view.instancer || d0_view.type != d1_view.type ||
-				d0_view.properties.GetNumProperties() != d1_view.properties.GetNumProperties())
+				d0_view.properties.GetNumProperties() != d1_view.properties.GetNumProperties() || d0_view.paint_area != d1_view.paint_area)
 			{
 			{
 				// Incompatible decorators, fall back to discrete interpolation.
 				// Incompatible decorators, fall back to discrete interpolation.
 				return DiscreteInterpolation();
 				return DiscreteInterpolation();
 			}
 			}
 
 
-			decorator->list.push_back(DecoratorDeclaration{d0_view.type, d0_view.instancer, PropertyDictionary()});
+			decorator->list.push_back(DecoratorDeclaration{d0_view.type, d0_view.instancer, PropertyDictionary(), d0_view.paint_area});
 			PropertyDictionary& props = decorator->list.back().properties;
 			PropertyDictionary& props = decorator->list.back().properties;
 
 
 			const auto& props0 = d0_view.properties.GetProperties();
 			const auto& props0 = d0_view.properties.GetProperties();
@@ -269,7 +270,7 @@ static Property InterpolateProperties(const Property& p0, const Property& p1, fl
 			if (!dbig_view.instancer)
 			if (!dbig_view.instancer)
 				return DiscreteInterpolation();
 				return DiscreteInterpolation();
 
 
-			decorator->list.push_back(DecoratorDeclaration{dbig_view.type, dbig_view.instancer, PropertyDictionary()});
+			decorator->list.push_back(DecoratorDeclaration{dbig_view.type, dbig_view.instancer, PropertyDictionary(), dbig_view.paint_area});
 			DecoratorDeclaration& d_new = decorator->list.back();
 			DecoratorDeclaration& d_new = decorator->list.back();
 
 
 			const PropertySpecification& specification = d_new.instancer->GetPropertySpecification();
 			const PropertySpecification& specification = d_new.instancer->GetPropertySpecification();

+ 13 - 7
Source/Core/ElementDecoration.cpp

@@ -87,16 +87,22 @@ void ElementDecoration::InstanceDecorators()
 		}
 		}
 
 
 		const DecoratorPtrList& decorator_list = style_sheet->InstanceDecorators(*decorators_ptr, source);
 		const DecoratorPtrList& decorator_list = style_sheet->InstanceDecorators(*decorators_ptr, source);
+		RMLUI_ASSERT(decorator_list.empty() || decorator_list.size() == decorators_ptr->list.size());
 
 
-		for (const SharedPtr<const Decorator>& decorator : decorator_list)
+		for (size_t i = 0; i < decorator_list.size() && i < decorators_ptr->list.size(); i++)
 		{
 		{
+			const SharedPtr<const Decorator>& decorator = decorator_list[i];
 			if (decorator)
 			if (decorator)
 			{
 			{
-				DecoratorEntry decorator_handle;
-				decorator_handle.decorator_data = 0;
-				decorator_handle.decorator = decorator;
-
-				decorators.push_back(std::move(decorator_handle));
+				DecoratorEntry entry;
+				entry.decorator_data = 0;
+				entry.decorator = decorator;
+				entry.paint_area = decorators_ptr->list[i].paint_area;
+				if (entry.paint_area == BoxArea::Auto)
+					entry.paint_area = BoxArea::Padding;
+
+				RMLUI_ASSERT(entry.paint_area >= BoxArea::Border && entry.paint_area <= BoxArea::Content);
+				decorators.push_back(std::move(entry));
 			}
 			}
 		}
 		}
 	}
 	}
@@ -145,7 +151,7 @@ void ElementDecoration::ReloadDecoratorsData()
 			if (decorator.decorator_data)
 			if (decorator.decorator_data)
 				decorator.decorator->ReleaseElementData(decorator.decorator_data);
 				decorator.decorator->ReleaseElementData(decorator.decorator_data);
 
 
-			decorator.decorator_data = decorator.decorator->GenerateElementData(element);
+			decorator.decorator_data = decorator.decorator->GenerateElementData(element, decorator.paint_area);
 		}
 		}
 
 
 		for (FilterEntryList* list : {&filters, &backdrop_filters})
 		for (FilterEntryList* list : {&filters, &backdrop_filters})

+ 1 - 0
Source/Core/ElementDecoration.h

@@ -70,6 +70,7 @@ private:
 	struct DecoratorEntry {
 	struct DecoratorEntry {
 		SharedPtr<const Decorator> decorator;
 		SharedPtr<const Decorator> decorator;
 		DecoratorDataHandle decorator_data;
 		DecoratorDataHandle decorator_data;
+		BoxArea paint_area;
 	};
 	};
 	using DecoratorEntryList = Vector<DecoratorEntry>;
 	using DecoratorEntryList = Vector<DecoratorEntry>;
 
 

+ 47 - 4
Source/Core/PropertyParserDecorator.cpp

@@ -35,6 +35,12 @@
 
 
 namespace Rml {
 namespace Rml {
 
 
+const SmallUnorderedMap<String, BoxArea> PropertyParserDecorator::area_keywords = {
+	{"border-box", BoxArea::Border},
+	{"padding-box", BoxArea::Padding},
+	{"content-box", BoxArea::Content},
+};
+
 PropertyParserDecorator::PropertyParserDecorator() {}
 PropertyParserDecorator::PropertyParserDecorator() {}
 
 
 PropertyParserDecorator::~PropertyParserDecorator() {}
 PropertyParserDecorator::~PropertyParserDecorator() {}
@@ -44,9 +50,11 @@ bool PropertyParserDecorator::ParseValue(Property& property, const String& decor
 	// Decorators are declared as
 	// Decorators are declared as
 	//   decorator: <decorator-value>[, <decorator-value> ...];
 	//   decorator: <decorator-value>[, <decorator-value> ...];
 	// Where <decorator-value> is either a @decorator name:
 	// Where <decorator-value> is either a @decorator name:
-	//   decorator: invader-theme-background, ...;
+	//   decorator: invader-theme-background <paint-area>?, ...;
 	// or is an anonymous decorator with inline properties
 	// or is an anonymous decorator with inline properties
-	//   decorator: tiled-box( <shorthand properties> ), ...;
+	//   decorator: tiled-box( <shorthand properties> ) <paint-area>?, ...;
+	// where <paint-area> is one of
+	//   border-box, padding-box, content-box
 
 
 	if (decorator_string_value.empty() || decorator_string_value == "none")
 	if (decorator_string_value.empty() || decorator_string_value == "none")
 	{
 	{
@@ -57,6 +65,8 @@ bool PropertyParserDecorator::ParseValue(Property& property, const String& decor
 
 
 	RMLUI_ZoneScoped;
 	RMLUI_ZoneScoped;
 
 
+	const BoxArea default_paint_area = BoxArea::Padding;
+
 	// Make sure we don't split inside the parenthesis since they may appear in decorator shorthands.
 	// Make sure we don't split inside the parenthesis since they may appear in decorator shorthands.
 	StringList decorator_string_list;
 	StringList decorator_string_list;
 	StringUtilities::ExpandString(decorator_string_list, decorator_string_value, ',', '(', ')');
 	StringUtilities::ExpandString(decorator_string_list, decorator_string_value, ',', '(', ')');
@@ -72,10 +82,33 @@ bool PropertyParserDecorator::ParseValue(Property& property, const String& decor
 		const size_t shorthand_close = decorator_string.rfind(')');
 		const size_t shorthand_close = decorator_string.rfind(')');
 		const bool invalid_parenthesis = (shorthand_open == String::npos || shorthand_close == String::npos || shorthand_open >= shorthand_close);
 		const bool invalid_parenthesis = (shorthand_open == String::npos || shorthand_close == String::npos || shorthand_open >= shorthand_close);
 
 
+		// Find the paint area for the decorator.
+		BoxArea paint_area = default_paint_area;
+
+		// Look-up keywords for customized paint area.
+		{
+			const size_t keywords_begin = (invalid_parenthesis ? decorator_string.find(' ') : shorthand_close + 1);
+			StringList keywords;
+			if (keywords_begin < decorator_string.size())
+				StringUtilities::ExpandString(keywords, decorator_string.substr(keywords_begin), ' ');
+
+			for (const String& keyword : keywords)
+			{
+				if (keyword.empty())
+					continue;
+
+				auto it = area_keywords.find(StringUtilities::ToLower(keyword));
+				if (it == area_keywords.end())
+					return false; // Bail out if we have an invalid keyword.
+
+				paint_area = it->second;
+			}
+		}
+
 		if (invalid_parenthesis)
 		if (invalid_parenthesis)
 		{
 		{
 			// We found no parenthesis, that means the value must be a name of a @decorator rule.
 			// We found no parenthesis, that means the value must be a name of a @decorator rule.
-			decorators.list.emplace_back(DecoratorDeclaration{decorator_string, nullptr, {}});
+			decorators.list.emplace_back(DecoratorDeclaration{decorator_string, nullptr, {}, paint_area});
 		}
 		}
 		else
 		else
 		{
 		{
@@ -105,7 +138,7 @@ bool PropertyParserDecorator::ParseValue(Property& property, const String& decor
 			// Set unspecified values to their defaults
 			// Set unspecified values to their defaults
 			specification.SetPropertyDefaults(properties);
 			specification.SetPropertyDefaults(properties);
 
 
-			decorators.list.emplace_back(DecoratorDeclaration{type, instancer, std::move(properties)});
+			decorators.list.emplace_back(DecoratorDeclaration{type, instancer, std::move(properties), paint_area});
 		}
 		}
 	}
 	}
 
 
@@ -118,4 +151,14 @@ bool PropertyParserDecorator::ParseValue(Property& property, const String& decor
 	return true;
 	return true;
 }
 }
 
 
+String PropertyParserDecorator::ConvertAreaToString(BoxArea area)
+{
+	for (const auto& it : area_keywords)
+	{
+		if (it.second == area)
+			return it.first;
+	}
+	return String();
+}
+
 } // namespace Rml
 } // namespace Rml

+ 5 - 0
Source/Core/PropertyParserDecorator.h

@@ -44,6 +44,11 @@ public:
 
 
 	/// Called to parse a decorator declaration.
 	/// Called to parse a decorator declaration.
 	bool ParseValue(Property& property, const String& value, const ParameterMap& parameters) const override;
 	bool ParseValue(Property& property, const String& value, const ParameterMap& parameters) const override;
+
+	static String ConvertAreaToString(BoxArea area);
+
+private:
+	static const SmallUnorderedMap<String, BoxArea> area_keywords;
 };
 };
 
 
 } // namespace Rml
 } // namespace Rml

+ 14 - 3
Source/Core/TypeConverter.cpp

@@ -37,6 +37,7 @@
 #include "../../Include/RmlUi/Core/StyleSheetTypes.h"
 #include "../../Include/RmlUi/Core/StyleSheetTypes.h"
 #include "../../Include/RmlUi/Core/Transform.h"
 #include "../../Include/RmlUi/Core/Transform.h"
 #include "../../Include/RmlUi/Core/TransformPrimitive.h"
 #include "../../Include/RmlUi/Core/TransformPrimitive.h"
+#include "PropertyParserDecorator.h"
 #include "TransformUtilities.h"
 #include "TransformUtilities.h"
 
 
 namespace Rml {
 namespace Rml {
@@ -163,6 +164,16 @@ bool TypeConverter<AnimationList, String>::Convert(const AnimationList& src, Str
 	return true;
 	return true;
 }
 }
 
 
+template <typename EffectDeclaration>
+void AppendPaintArea(const EffectDeclaration& /*declaration*/, String& /*dest*/)
+{}
+template <>
+void AppendPaintArea(const DecoratorDeclaration& declaration, String& dest)
+{
+	if (declaration.paint_area >= BoxArea::Border && declaration.paint_area <= BoxArea::Padding)
+		dest += " " + PropertyParserDecorator::ConvertAreaToString(declaration.paint_area);
+}
+
 template <typename EffectsPtr>
 template <typename EffectsPtr>
 static bool ConvertEffectToString(const EffectsPtr& src, String& dest, const String& separator)
 static bool ConvertEffectToString(const EffectsPtr& src, String& dest, const String& separator)
 {
 {
@@ -176,10 +187,10 @@ static bool ConvertEffectToString(const EffectsPtr& src, String& dest, const Str
 		for (const auto& declaration : src->list)
 		for (const auto& declaration : src->list)
 		{
 		{
 			dest += declaration.type;
 			dest += declaration.type;
-			if (auto instancer = declaration.instancer)
-			{
+			if (auto* instancer = declaration.instancer)
 				dest += '(' + instancer->GetPropertySpecification().PropertiesToString(declaration.properties, false, ' ') + ')';
 				dest += '(' + instancer->GetPropertySpecification().PropertiesToString(declaration.properties, false, ' ') + ')';
-			}
+
+			AppendPaintArea(declaration, dest);
 			if (&declaration != &src->list.back())
 			if (&declaration != &src->list.back())
 				dest += separator;
 				dest += separator;
 		}
 		}