<commit_before>using Uno;
using Uno.Graphics;
using Uno.Collections;

namespace Fuse.Elements
{
	internal class ElementBatchEntry
	{
		public ElementBatchEntry(Element elm)
		{
			_elm = elm;
			_opacity = GetEffectiveOpacity();
		}

		float GetEffectiveOpacity()
		{
			if (_elm.Visibility == Visibility.Visible)
			        return _elm.Opacity;
			return 0.0f;
		}

		public void InvalidateVisual()
		{
			_atlas.InvalidateElement(_elm);
		}

		public void InvalidateVisualComposition()
		{
			float opacity = GetEffectiveOpacity();

			if (_opacity != opacity)
			{
				if (_batch != null)
					_batch.InvalidateOpacity(_elm);

				_opacity = opacity;
			}
		}

		public void InvalidateRenderBounds()
		{
			if (_batch != null)
			{
				_batch._elementBatcher._reinsertCheckList.Add(this);
				_batch.InvalidateRenderBounds(_elm);
			}
		}

		public void InvalidateTransform()
		{
			if (_batch != null)
				_batch.InvalidateTransform(_elm);
		}

		public void OnRemoved()
		{
			if (_atlas != null)
				_atlas.RemoveElement(_elm);

			if (_batch != null)
				_batch.RemoveElement(_elm);
		}

		public ElementAtlas _atlas;
		public ElementBatch _batch;
		public readonly Element _elm;
		public Recti AtlasRect;
		public int2 DrawingOffset;
		public float _opacity;
		public bool IsValid;
	}

	internal class ElementBatch : IElementBatchDrawable
	{
		public readonly ElementBatcher _elementBatcher;
		public readonly ElementAtlas _elementAtlas;

		bool _indexBufferValid, _vertexPositionBufferValid, _vertexTexCoordBufferValid;
		IndexBuffer _indexBuffer;
		VertexAttributeInfo _positionInfo;
		VertexAttributeInfo _texCoordInfo;
		int _prevElementCount;

		public ElementBatch(ElementBatcher elementBatcher, ElementAtlas elementAtlas)
		{
			_elementBatcher = elementBatcher;
			_elementAtlas = elementAtlas;

			_positionInfo = new VertexAttributeInfo();
			_positionInfo.BufferOffset = 0;
			_positionInfo.BufferStride = sizeof(float3);
			_positionInfo.Type = VertexAttributeType.Float3;
			_positionInfo.Buffer = new VertexBuffer(BufferUsage.Dynamic);

			_texCoordInfo = new VertexAttributeInfo();
			_texCoordInfo.BufferOffset = 0;
			_texCoordInfo.BufferStride = sizeof(float2);
			_texCoordInfo.Type = VertexAttributeType.Float2;
			_texCoordInfo.Buffer = new VertexBuffer(BufferUsage.Immutable);
		}

		public void Dispose()
		{
			foreach (var elm in _elements)
				elm._batch = null;

			if (_positionInfo.Buffer != null)
				_positionInfo.Buffer.Dispose();

			if (_texCoordInfo.Buffer != null)
				_texCoordInfo.Buffer.Dispose();

			if (_indexBuffer != null)
				_indexBuffer.Dispose();
		}

		internal static Recti ConservativelySnapToCoveringIntegers(Rect r)
		{
			// To prevent translations from affecting the size, round off origin and size
			// separately. And because origin might be rounded down while size not, we need
			// to add one to the width to be sure.

			int2 origin = (int2)Math.Floor(r.Minimum);
			int2 size = (int2)Math.Ceil(r.Size + 0.01f);
			return new Recti(origin.X,
			                 origin.Y,
			                 origin.X + size.X + 1,
			                 origin.Y + size.Y + 1);
		}

		public static Recti GetCachingRect(Element elm)
		{
			var bounds = elm.RenderBoundsWithEffects;
			if (bounds.IsInfinite || bounds.IsEmpty)
				throw new Exception( "element has no caching rect" );

			const int CachingRectPadding = 1;
			
			return Recti.Inflate(ConservativelySnapToCoveringIntegers(Rect.Scale(bounds.FlatRect,
				elm.AbsoluteZoom)), CachingRectPadding);
		}

		Box GetRenderBounds(Element elm)
		{
			var t = elm.InternLocalTransformInternal;
			return VisualBounds.BoxTransform((Box)elm.LocalRenderBounds, t);
		}

		VisualBounds CalcRenderBounds()
		{
			if (_elements.Count == 0) return VisualBounds.Empty;

			var box = GetRenderBounds(_elements[0]._elm);
			for (int i = 1; i < _elements.Count; i++)
			{
				var b = GetRenderBounds(_elements[i]._elm);
				if (b.Minimum.X < box.Minimum.X) box.Minimum.X = b.Minimum.X;
				if (b.Minimum.Y < box.Minimum.Y) box.Minimum.Y = b.Minimum.Y;
				if (b.Minimum.Z < box.Minimum.Z) box.Minimum.Z = b.Minimum.Z;
				if (b.Maximum.X > box.Maximum.X) box.Maximum.X = b.Maximum.X;
				if (b.Maximum.Y > box.Maximum.Y) box.Maximum.Y = b.Maximum.Y;
				if (b.Maximum.Z > box.Maximum.Z) box.Maximum.Z = b.Maximum.Z;
			}
			return VisualBounds.Box(box);
		}

		VisualBounds _renderBounds;
		public VisualBounds RenderBounds
		{
			get
			{
				if (_renderBounds == null)
				{
					_renderBounds = CalcRenderBounds();
				}
				return _renderBounds;
			}
		}

		List<ElementBatchEntry> _elements = new List<ElementBatchEntry>();
		public void AddElement(Element elm)
		{
			if (elm.ElementBatchEntry._atlas != _elementAtlas)
				throw new Exception("wrong atlas, stupid!");

			var entry = elm.ElementBatchEntry;
			entry._batch = this;
			_elements.Add(entry);
			_indexBufferValid = false;
			_vertexPositionBufferValid = false;<commit_msg>Account for Empty and Infinite bounds<commit_after>using Uno;
using Uno.Graphics;
using Uno.Collections;

namespace Fuse.Elements
{
	internal class ElementBatchEntry
	{
		public ElementBatchEntry(Element elm)
		{
			_elm = elm;
			_opacity = GetEffectiveOpacity();
		}

		float GetEffectiveOpacity()
		{
			if (_elm.Visibility == Visibility.Visible)
			        return _elm.Opacity;
			return 0.0f;
		}

		public void InvalidateVisual()
		{
			_atlas.InvalidateElement(_elm);
		}

		public void InvalidateVisualComposition()
		{
			float opacity = GetEffectiveOpacity();

			if (_opacity != opacity)
			{
				if (_batch != null)
					_batch.InvalidateOpacity(_elm);

				_opacity = opacity;
			}
		}

		public void InvalidateRenderBounds()
		{
			if (_batch != null)
			{
				_batch._elementBatcher._reinsertCheckList.Add(this);
				_batch.InvalidateRenderBounds(_elm);
			}
		}

		public void InvalidateTransform()
		{
			if (_batch != null)
				_batch.InvalidateTransform(_elm);
		}

		public void OnRemoved()
		{
			if (_atlas != null)
				_atlas.RemoveElement(_elm);

			if (_batch != null)
				_batch.RemoveElement(_elm);
		}

		public ElementAtlas _atlas;
		public ElementBatch _batch;
		public readonly Element _elm;
		public Recti AtlasRect;
		public int2 DrawingOffset;
		public float _opacity;
		public bool IsValid;
	}

	internal class ElementBatch : IElementBatchDrawable
	{
		public readonly ElementBatcher _elementBatcher;
		public readonly ElementAtlas _elementAtlas;

		bool _indexBufferValid, _vertexPositionBufferValid, _vertexTexCoordBufferValid;
		IndexBuffer _indexBuffer;
		VertexAttributeInfo _positionInfo;
		VertexAttributeInfo _texCoordInfo;
		int _prevElementCount;

		public ElementBatch(ElementBatcher elementBatcher, ElementAtlas elementAtlas)
		{
			_elementBatcher = elementBatcher;
			_elementAtlas = elementAtlas;

			_positionInfo = new VertexAttributeInfo();
			_positionInfo.BufferOffset = 0;
			_positionInfo.BufferStride = sizeof(float3);
			_positionInfo.Type = VertexAttributeType.Float3;
			_positionInfo.Buffer = new VertexBuffer(BufferUsage.Dynamic);

			_texCoordInfo = new VertexAttributeInfo();
			_texCoordInfo.BufferOffset = 0;
			_texCoordInfo.BufferStride = sizeof(float2);
			_texCoordInfo.Type = VertexAttributeType.Float2;
			_texCoordInfo.Buffer = new VertexBuffer(BufferUsage.Immutable);
		}

		public void Dispose()
		{
			foreach (var elm in _elements)
				elm._batch = null;

			if (_positionInfo.Buffer != null)
				_positionInfo.Buffer.Dispose();

			if (_texCoordInfo.Buffer != null)
				_texCoordInfo.Buffer.Dispose();

			if (_indexBuffer != null)
				_indexBuffer.Dispose();
		}

		internal static Recti ConservativelySnapToCoveringIntegers(Rect r)
		{
			// To prevent translations from affecting the size, round off origin and size
			// separately. And because origin might be rounded down while size not, we need
			// to add one to the width to be sure.

			int2 origin = (int2)Math.Floor(r.Minimum);
			int2 size = (int2)Math.Ceil(r.Size + 0.01f);
			return new Recti(origin.X,
			                 origin.Y,
			                 origin.X + size.X + 1,
			                 origin.Y + size.Y + 1);
		}

		public static Recti GetCachingRect(Element elm)
		{
			var bounds = elm.RenderBoundsWithEffects;
			if (bounds.IsInfinite || bounds.IsEmpty)
				throw new Exception( "element has no caching rect" );

			const int CachingRectPadding = 1;
			
			return Recti.Inflate(ConservativelySnapToCoveringIntegers(Rect.Scale(bounds.FlatRect,
				elm.AbsoluteZoom)), CachingRectPadding);
		}

		VisualBounds CalcRenderBounds()
		{
			bool hasAnyBounds = false;
			Box box;
			for (var i = 0; i < _elements.Count; i++)
			{
				var lrb = elm.LocalRenderBounds;
				if (lrb == VisualBounds.Empty) continue;
				if (lrb == VisualBounds.Infinite) return VisualBounds.Infinite;
				if (!hasAnyBounds)
				{
					box = GetRenderBounds(_elements[0]._elm);
					hasAnyBounds = true;
				}
				else
				{
					var b = VisualBounds.BoxTransform((Box)lrb, elm.InternLocalTransformInternal);
					if (b.Minimum.X < box.Minimum.X) box.Minimum.X = b.Minimum.X;
					if (b.Minimum.Y < box.Minimum.Y) box.Minimum.Y = b.Minimum.Y;
					if (b.Minimum.Z < box.Minimum.Z) box.Minimum.Z = b.Minimum.Z;
					if (b.Maximum.X > box.Maximum.X) box.Maximum.X = b.Maximum.X;
					if (b.Maximum.Y > box.Maximum.Y) box.Maximum.Y = b.Maximum.Y;
					if (b.Maximum.Z > box.Maximum.Z) box.Maximum.Z = b.Maximum.Z;
				}
			}
			
			if (!hasAnyBounds) return VisualBounds.Empty;
			else return VisualBounds.Box(box);
		}

		VisualBounds _renderBounds;
		public VisualBounds RenderBounds
		{
			get
			{
				if (_renderBounds == null)
				{
					_renderBounds = CalcRenderBounds();
				}
				return _renderBounds;
			}
		}

		List<ElementBatchEntry> _elements = new List<ElementBatchEntry>();
		public void AddElement(Element elm)
		{
			if (elm.ElementBatchEntry._atlas != _elementAtlas)
				throw new Exception("wrong atlas, stupid!");

			var entry = elm.ElementBatchEntry;
			entry._batch = this;
			_elements.Add(entry);
			_indexBufferValid = false;
			_vertexPositionBufferValid = false;
{'fraction_non_alphanumeric': 0.09994033412887827, 'fraction_numerical': 0.004276054097056484, 'mean_word_length': 3.4129003949100483, 'pattern_counts': {'":': 0, '<': 15, '<?xml version=': 0, '>': 13, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1205966', 'n_tokens_mistral': 3935, 'n_tokens_neox': 3203, 'n_words': 729}