Browse Source

Determine computed value for fonts

Michael Ragazzon 6 years ago
parent
commit
04dc275c4e

+ 3 - 0
Include/Rocket/Core/Element.h

@@ -61,6 +61,7 @@ class PropertyDictionary;
 class RenderInterface;
 class StyleSheet;
 struct ElementMeta;
+namespace RCSS { struct ComputedValues; }
 
 /**
 	A generic element in the DOM tree.
@@ -621,6 +622,8 @@ public:
 	/// @param[in] event The event to process.
 	virtual void ProcessEvent(Event& event);
 
+	const RCSS::ComputedValues& GetComputedValues() const;
+
 protected:
 	void Update();
 	void Render();

+ 2 - 1
Include/Rocket/Core/ElementUtilities.h

@@ -40,6 +40,7 @@ class Context;
 class FontFaceHandle;
 class RenderInterface;
 class ViewState;
+namespace RCSS { struct ComputedValues; }
 
 /**
 	Utility functions for dealing with elements.
@@ -81,7 +82,7 @@ public:
 	/// Returns an element's font face.
 	/// @param[in] element The element to determine the font face for.
 	/// @return The element's font face. This will be NULL if no valid RCSS font styles have been set up for this element.
-	static FontFaceHandle* GetFontFaceHandle(Element* element);
+	static FontFaceHandle* GetFontFaceHandle(const RCSS::ComputedValues& computed_values);
 	/// Returns an element's density-independent pixel ratio, defined by it's context
 	/// @param[in] element The element to determine the density-independent pixel ratio for.
 	/// @return The density-independent pixel ratio of the context, or 1.0 if no context assigned.

+ 1 - 0
Include/Rocket/Core/Property.h

@@ -81,6 +81,7 @@ public:
 		LENGTH = PX | DP | PPI_UNIT | EM | REM,
 		LENGTH_PERCENT = LENGTH | PERCENT,
 		NUMBER_LENGTH_PERCENT = NUMBER | LENGTH | PERCENT,
+		ABSOLUTE_LENGTH = PX | DP | PPI_UNIT,
 		ANGLE = NUMBER | DEG | RAD
 	};
 

+ 22 - 1
Source/Core/Element.cpp

@@ -209,6 +209,22 @@ void Element::Update()
 	style->UpdateDefinition();
 	scroll->Update();
 
+	if(all_properties_dirty || dirty_properties.count("font_family"))
+	{
+		using namespace RCSS;
+		const ComputedValues* parent_values = (parent ? &parent->GetComputedValues() : nullptr);
+		float ppi = GetRenderInterface()->GetPixelsPerInch();
+		float dp_ratio = 1.0f;
+		const ComputedValues* document_values = nullptr;
+		if (auto doc = GetOwnerDocument())
+		{
+			document_values = &doc->GetComputedValues();
+			if (auto context = doc->GetContext())
+				dp_ratio = context->GetDensityIndependentPixelRatio();
+		}
+		style->ComputeValues(element_meta->computed_values, parent_values, document_values, dp_ratio, ppi);
+	}
+
 	UpdateAnimation();
 	AdvanceAnimations();
 
@@ -1846,7 +1862,7 @@ void Element::OnPropertyChange(const PropertyNameList& changed_properties)
 			old_em = font_face_handle->GetLineHeight();
 
 		// Fetch the new font face.
-		FontFaceHandle * new_font_face_handle = ElementUtilities::GetFontFaceHandle(this);
+		FontFaceHandle * new_font_face_handle = ElementUtilities::GetFontFaceHandle(element_meta->computed_values);
 
 		// If this is different from our current font face, then we've got to nuke
 		// all our characters and tell our parent that we have to be re-laid out.
@@ -2124,6 +2140,11 @@ void Element::ProcessEvent(Event& event)
 	}
 }
 
+const RCSS::ComputedValues& Element::GetComputedValues() const
+{
+	return element_meta->computed_values;
+}
+
 void Element::GetRML(String& content)
 {
 	// First we start the open tag, add the attributes then close the open tag.

+ 173 - 1
Source/Core/ElementStyle.cpp

@@ -43,10 +43,15 @@
 #include "ElementDecoration.h"
 #include "ElementDefinition.h"
 #include "FontFaceHandle.h"
+#include "RCSS.h"
+
 
 namespace Rocket {
 namespace Core {
 
+static const RCSS::ComputedValues DefaultComputedValues;
+
+
 ElementStyle::ElementStyle(Element* _element)
 {
 	local_properties = NULL;
@@ -618,7 +623,7 @@ float ElementStyle::ResolveProperty(const String& name, float base_value)
 			if (owner_document == NULL)
 				return 0;
 
-			base_value = element->GetOwnerDocument()->ResolveProperty(FONT_SIZE, 0);
+			base_value = owner_document->ResolveProperty(FONT_SIZE, 0);
 		}
 		else
 		{
@@ -1039,5 +1044,172 @@ const Property *ElementStyle::GetTransformOriginZ()
 	return element->GetProperty(TRANSFORM_ORIGIN_Z);
 }
 
+
+
+static float ComputeLength(const Property* property, float font_size, float document_font_size, float dp_ratio, float pixels_per_inch)
+{
+	if (!property)
+	{
+		ROCKET_ERROR;
+		return 0.0f;
+	}
+
+	// TODO
+	float base_value = 1.0f;
+
+	switch (property->unit)
+	{
+	case Property::NUMBER:
+	case Property::PX:
+	case Property::RAD:
+		return property->value.Get< float >();
+
+	case Property::PERCENT:
+		return base_value * property->value.Get< float >()* 0.01f;
+
+	case Property::EM:
+		return property->value.Get< float >() * font_size;
+	case Property::REM:
+		return property->value.Get< float >() * document_font_size;
+	case Property::DP:
+		return property->value.Get< float >() * dp_ratio;
+
+	case Property::DEG:
+		return Math::DegreesToRadians(property->value.Get< float >());
+	}
+
+	// Values based on pixels-per-inch.
+	if (property->unit & Property::PPI_UNIT)
+	{
+		float inch = property->value.Get< float >() * pixels_per_inch;
+
+		switch (property->unit)
+		{
+		case Property::INCH: // inch
+			return inch;
+		case Property::CM: // centimeter
+			return inch * (1.0f / 2.54f);
+		case Property::MM: // millimeter
+			return inch * (1.0f / 25.4f);
+		case Property::PT: // point
+			return inch * (1.0f / 72.0f);
+		case Property::PC: // pica
+			return inch * (1.0f / 6.0f);
+		}
+	}
+
+	// We're not a numeric property; return 0.
+	return 0.0f;
+}
+
+
+
+
+static float ComputeAbsoluteLength(const Property& property, float dp_ratio, float pixels_per_inch)
+{
+	ROCKET_ASSERT(property.unit & Property::ABSOLUTE_LENGTH);
+
+	switch (property.unit)
+	{
+	case Property::PX:
+		return property.value.Get< float >();
+	case Property::DP:
+		return property.value.Get< float >()* dp_ratio;
+	default:
+		// Values based on pixels-per-inch.
+		if (property.unit & Property::PPI_UNIT)
+		{
+			float inch = property.value.Get< float >() * pixels_per_inch;
+
+			switch (property.unit)
+			{
+			case Property::INCH: // inch
+				return inch;
+			case Property::CM: // centimeter
+				return inch * (1.0f / 2.54f);
+			case Property::MM: // millimeter
+				return inch * (1.0f / 25.4f);
+			case Property::PT: // point
+				return inch * (1.0f / 72.0f);
+			case Property::PC: // pica
+				return inch * (1.0f / 6.0f);
+			}
+		}
+	}
+
+	ROCKET_ERROR;
+	return 0.0f;
+}
+
+
+
+// Resolves one of this element's properties.
+static float ComputeFontsize(const Property& property, const RCSS::ComputedValues& values, const RCSS::ComputedValues* parent_values, const RCSS::ComputedValues* document_values, float dp_ratio, float pixels_per_inch)
+{
+	// The calculated value of the font-size property is inherited, so we need to check if this
+	// is an inherited property. If so, then we return our parent's font size instead.
+	if (property.unit & Property::RELATIVE_UNIT)
+	{
+		float multiplier = 1.0f;
+
+		switch (property.unit)
+		{
+		case Property::PERCENT:
+			multiplier = 0.01f;
+			[[fallthrough]];
+		case Property::EM:
+			if (!parent_values)
+				return 0;
+			return property.value.Get< float >() * multiplier * parent_values->font_size;
+
+		case Property::REM:
+			if (!document_values)
+				return 0;
+			// If the current element is a document, the rem unit is relative to the default size
+			if(&values == document_values)
+				return property.value.Get< float >() * DefaultComputedValues.font_size;
+			// Otherwise it is relative to the document font size
+			return property.value.Get< float >() * document_values->font_size;
+		default:
+			ROCKET_ERRORMSG("A relative unit must be percentage, em or rem.");
+		}
+	}
+
+	return ComputeAbsoluteLength(property, dp_ratio, pixels_per_inch);
+}
+
+
+
+void ElementStyle::ComputeValues(RCSS::ComputedValues& values, const RCSS::ComputedValues* parent_values, const RCSS::ComputedValues* document_values, float dp_ratio, float pixels_per_inch)
+{
+	// TODO: Iterate through dirty values, and compute corresponding properties.
+	// Important: Always do font-size first if dirty, because of em-relative values.
+
+	if (auto p = GetLocalProperty(FONT_SIZE))
+		values.font_size = ComputeFontsize(*p, values, parent_values, document_values, dp_ratio, pixels_per_inch);
+	else if (parent_values)
+		values.font_size = parent_values->font_size;
+
+	if (auto p = GetLocalProperty(FONT_FAMILY))
+		values.font_family = p->Get<String>();
+	else if (parent_values)
+		values.font_family = parent_values->font_family;
+
+	if (auto p = GetLocalProperty(FONT_CHARSET))
+		values.font_charset = p->Get<String>();
+	else if (parent_values)
+		values.font_charset = parent_values->font_charset;
+
+	if (auto p = GetLocalProperty(FONT_STYLE))
+		values.font_style = (RCSS::FontStyle)p->Get< int >();
+	else if (parent_values)
+		values.font_style = parent_values->font_style;
+
+	if (auto p = GetLocalProperty(FONT_WEIGHT))
+		values.font_weight = (RCSS::FontWeight)p->Get< int >();
+	else if (parent_values)
+		values.font_weight = parent_values->font_weight;
+}
+
 }
 }

+ 5 - 0
Source/Core/ElementStyle.h

@@ -34,6 +34,8 @@
 namespace Rocket {
 namespace Core {
 
+namespace RCSS { struct ComputedValues; }
+
 class ElementStyleCache;
 
 /**
@@ -213,6 +215,9 @@ public:
 	/// Returns 'transform-origin-z' property value from element's style or local cache.
 	const Property *GetTransformOriginZ();
 
+
+	void ComputeValues(RCSS::ComputedValues& values, const RCSS::ComputedValues* parent_values, const RCSS::ComputedValues* document_values, float dp_ratio, float pixels_per_inch);
+
 private:
 	// Sets a single property as dirty.
 	void DirtyProperty(const String& property);

+ 7 - 7
Source/Core/ElementUtilities.cpp

@@ -34,6 +34,7 @@
 #include "../../Include/Rocket/Core.h"
 #include "../../Include/Rocket/Core/TransformPrimitive.h"
 #include "ElementStyle.h"
+#include "RCSS.h"
 
 namespace Rocket {
 namespace Core {
@@ -113,16 +114,15 @@ void ElementUtilities::GetElementsByClassName(ElementList& elements, Element* ro
 }
 
 // Returns the element's font face.
-FontFaceHandle* ElementUtilities::GetFontFaceHandle(Element* element)
+FontFaceHandle* ElementUtilities::GetFontFaceHandle(const RCSS::ComputedValues& computed_values)
 {
+	static const String default_charset = "U+0020-007E";
 	// Fetch the new font face.
-	String font_family = element->GetProperty(FONT_FAMILY)->value.Get< String >();
-	String font_charset = element->GetProperty(FONT_CHARSET)->value.Get< String >();
-	Font::Style font_style = (Font::Style) element->GetProperty(FONT_STYLE)->value.Get< int >();
-	Font::Weight font_weight = (Font::Weight) element->GetProperty(FONT_WEIGHT)->value.Get< int >();
-	int font_size = Math::RealToInteger(element->ResolveProperty(FONT_SIZE, 0));
 
-	FontFaceHandle* font = FontDatabase::GetFontFaceHandle(font_family, font_charset, font_style, font_weight, font_size);
+	const String& charset = (computed_values.font_charset.empty() ? default_charset : computed_values.font_charset);
+
+	// TODO Synchronize enums
+	FontFaceHandle* font = FontDatabase::GetFontFaceHandle(computed_values.font_family, charset, (Font::Style)computed_values.font_style, (Font::Weight)computed_values.font_weight, computed_values.font_size);
 	return font;
 }
 

+ 1 - 1
Source/Core/RCSS.h

@@ -127,7 +127,7 @@ struct ComputedValues
 	String font_charset; // empty is same as "U+0020-007E"
 	FontStyle font_style = FontStyle::Normal;
 	FontWeight font_weight = FontWeight::Normal;
-	LengthPercentage font_size;
+	float font_size = 12.f;
 
 	TextAlign text_align = TextAlign::Left;
 	TextDecoration text_decoration = TextDecoration::None;