static ClipCounts UpperBoundApproximateRectClippingResults(Vertex[] vertices, UInt16[] indices, Vector4 clipRectMinMax)
        {
            ClipCounts cc = new ClipCounts();

            cc.firstClippedIndex    = int.MaxValue;
            cc.firstDegenerateIndex = -1;
            cc.lastClippedIndex     = -1;

            int indexCount = indices.Length;

            for (int i = 0; i < indexCount; i += 3)
            {
                Vector3 v0 = vertices[indices[i]].position;
                Vector3 v1 = vertices[indices[i + 1]].position;
                Vector3 v2 = vertices[indices[i + 2]].position;

                Vector4 triRectMinMax;
                triRectMinMax.x = v0.x < v1.x ? v0.x : v1.x;
                triRectMinMax.x = triRectMinMax.x < v2.x ? triRectMinMax.x : v2.x;
                triRectMinMax.y = v0.y < v1.y ? v0.y : v1.y;
                triRectMinMax.y = triRectMinMax.y < v2.y ? triRectMinMax.y : v2.y;
                triRectMinMax.z = v0.x > v1.x ? v0.x : v1.x;
                triRectMinMax.z = triRectMinMax.z > v2.x ? triRectMinMax.z : v2.x;
                triRectMinMax.w = v0.y > v1.y ? v0.y : v1.y;
                triRectMinMax.w = triRectMinMax.w > v2.y ? triRectMinMax.w : v2.y;

                // Test if the rect is outside (degenerate triangle), or totally inside (not clipped),
                // else it is _probably_ clipped, but can still be either degenerate or unclipped
                if ((triRectMinMax.x >= clipRectMinMax.x) &&
                    (triRectMinMax.z <= clipRectMinMax.z) &&
                    (triRectMinMax.y >= clipRectMinMax.y) &&
                    (triRectMinMax.w <= clipRectMinMax.w))
                {
                    cc.firstDegenerateIndex = -1;
                    continue; // Not clipped
                }

                cc.firstClippedIndex = cc.firstClippedIndex < i ? cc.firstClippedIndex : i;
                cc.lastClippedIndex  = i + 2;
                if ((triRectMinMax.x >= clipRectMinMax.z) ||
                    (triRectMinMax.z <= clipRectMinMax.x) ||
                    (triRectMinMax.y >= clipRectMinMax.w) ||
                    (triRectMinMax.w <= clipRectMinMax.y))
                {
                    cc.firstDegenerateIndex = cc.firstDegenerateIndex == -1 ? i : cc.firstDegenerateIndex;
                    cc.degenerateTriangles++;
                }

                cc.firstDegenerateIndex = -1;
                cc.clippedTriangles++;
                cc.addedTriangles += 4; // Triangles clipping against corners may spawn more triangles
            }
            return(cc);
        }
        unsafe static void RectClip(Vertex[] vertices, UInt16[] indices, Vector4 clipRectMinMax, MeshWriteData mwd, ClipCounts cc, ref int newVertexCount)
        {
            int lastEffectiveClippedIndex = cc.lastClippedIndex;

            if (cc.firstDegenerateIndex != -1 && cc.firstDegenerateIndex < lastEffectiveClippedIndex)
            {
                lastEffectiveClippedIndex = cc.firstDegenerateIndex;
            }
            UInt16 nextNewVertex = (UInt16)vertices.Length;

            // Copy all non-clipped indices
            for (int i = 0; i < cc.firstClippedIndex; i++)
            {
                mwd.SetNextIndex(indices[i]);
            }

            // Clipped triangles
            UInt16 *it = stackalloc UInt16[3]; // Indices of the triangle
            Vertex *vt = stackalloc Vertex[3]; // Vertices of the triangle

            for (int i = cc.firstClippedIndex; i < lastEffectiveClippedIndex; i += 3)
            {
                it[0] = indices[i];
                it[1] = indices[i + 1];
                it[2] = indices[i + 2];
                vt[0] = vertices[it[0]];
                vt[1] = vertices[it[1]];
                vt[2] = vertices[it[2]];

                Vector4 triRectMinMax;
                triRectMinMax.x = vt[0].position.x < vt[1].position.x ? vt[0].position.x : vt[1].position.x;
                triRectMinMax.x = triRectMinMax.x < vt[2].position.x ? triRectMinMax.x : vt[2].position.x;
                triRectMinMax.y = vt[0].position.y < vt[1].position.y ? vt[0].position.y : vt[1].position.y;
                triRectMinMax.y = triRectMinMax.y < vt[2].position.y ? triRectMinMax.y : vt[2].position.y;
                triRectMinMax.z = vt[0].position.x > vt[1].position.x ? vt[0].position.x : vt[1].position.x;
                triRectMinMax.z = triRectMinMax.z > vt[2].position.x ? triRectMinMax.z : vt[2].position.x;
                triRectMinMax.w = vt[0].position.y > vt[1].position.y ? vt[0].position.y : vt[1].position.y;
                triRectMinMax.w = triRectMinMax.w > vt[2].position.y ? triRectMinMax.w : vt[2].position.y;

                // Test if the rect is outside (degenerate triangle), or totally inside (not clipped),
                // else it is _probably_ clipped, but can still be either degenerate or unclipped
                if ((triRectMinMax.x >= clipRectMinMax.x) &&
                    (triRectMinMax.z <= clipRectMinMax.z) &&
                    (triRectMinMax.y >= clipRectMinMax.y) &&
                    (triRectMinMax.w <= clipRectMinMax.w))
                {
                    // Clean triangle
                    mwd.SetNextIndex(it[0]);
                    mwd.SetNextIndex(it[1]);
                    mwd.SetNextIndex(it[2]);
                    continue;
                }
                if ((triRectMinMax.x >= clipRectMinMax.z) ||
                    (triRectMinMax.z <= clipRectMinMax.x) ||
                    (triRectMinMax.y >= clipRectMinMax.w) ||
                    (triRectMinMax.w <= clipRectMinMax.y))
                {
                    continue;  // Skip this triangle. It is fully clipped.
                }

                // The full shabang
                RectClipTriangle(vt, it, clipRectMinMax, mwd, ref nextNewVertex);
            }

            // Copy remaining non-clipped indices
            int indexCount = indices.Length;

            for (int i = cc.lastClippedIndex + 1; i < indexCount; i++)
            {
                mwd.SetNextIndex(indices[i]);
            }

            newVertexCount = nextNewVertex;
            mwd.m_Vertices = mwd.m_Vertices.Slice(0, newVertexCount);
            mwd.m_Indices  = mwd.m_Indices.Slice(0, mwd.currentIndex);
        }
        internal static void MakeVectorGraphicsStretchBackground(Vertex[] svgVertices, UInt16[] svgIndices, float svgWidth, float svgHeight, Rect targetRect, Rect sourceUV, ScaleMode scaleMode, Color tint, int settingIndexOffset, AllocMeshData meshAlloc, out int finalVertexCount, out int finalIndexCount)
        {
            // Determine position offset and scale according to scale mode
            Vector2 svgSubRectSize   = new Vector2(svgWidth * sourceUV.width, svgHeight * sourceUV.height);
            Vector2 svgSubRectOffset = new Vector2(sourceUV.xMin * svgWidth, sourceUV.yMin * svgHeight);
            Rect    svgSubRect       = new Rect(svgSubRectOffset, svgSubRectSize);

            bool    isSubRect = sourceUV.xMin != 0 || sourceUV.yMin != 0 || sourceUV.width != 1 || sourceUV.height != 1;
            float   srcAspect = svgSubRectSize.x / svgSubRectSize.y;
            float   destAspect = targetRect.width / targetRect.height;
            Vector2 posOffset, posScale;

            switch (scaleMode)
            {
            case ScaleMode.StretchToFill:
                posOffset  = new Vector2(0, 0);
                posScale.x = targetRect.width / svgSubRectSize.x;
                posScale.y = targetRect.height / svgSubRectSize.y;
                break;

            case ScaleMode.ScaleAndCrop:
                // ScaleAndCrop keeps the content centered to follow the same behavior as textures
                posOffset = new Vector2(0, 0);
                if (destAspect > srcAspect)
                {
                    // Fill on x and crop top/bottom sides
                    posScale.x = posScale.y = targetRect.width / svgSubRectSize.x;
                    var   height = targetRect.height / posScale.y;
                    float offset = svgSubRect.height / 2.0f - height / 2.0f;
                    posOffset.y      -= offset * posScale.y;
                    svgSubRect.y     += offset;
                    svgSubRect.height = height;
                    isSubRect         = true;
                }
                else if (destAspect < srcAspect)
                {
                    // Fill on y and crop left/right sides
                    posScale.x = posScale.y = targetRect.height / svgSubRectSize.y;
                    var   width  = targetRect.width / posScale.x;
                    float offset = svgSubRect.width / 2.0f - width / 2.0f;
                    posOffset.x     -= offset * posScale.x;
                    svgSubRect.x    += offset;
                    svgSubRect.width = width;
                    isSubRect        = true;
                }
                else
                {
                    posScale.x = posScale.y = targetRect.width / svgSubRectSize.x;      // Just scale, cropping is not involved
                }
                break;

            case ScaleMode.ScaleToFit:
                if (destAspect > srcAspect)
                {
                    // Fill on y and offset on x
                    posScale.x  = posScale.y = targetRect.height / svgSubRectSize.y;
                    posOffset.x = (targetRect.width - svgSubRectSize.x * posScale.x) * 0.5f;
                    posOffset.y = 0;
                }
                else
                {
                    // Fill on x and offset on y
                    posScale.x  = posScale.y = targetRect.width / svgSubRectSize.x;
                    posOffset.x = 0;
                    posOffset.y = (targetRect.height - svgSubRectSize.y * posScale.y) * 0.5f;
                }
                break;

            default:
                throw new NotImplementedException();
            }

            s_VectorGraphicsStretch.Begin();

            posOffset -= svgSubRectOffset * posScale;

            int        newVertexCount   = svgVertices.Length;
            int        newIndexCount    = svgIndices.Length;
            ClipCounts cc               = new ClipCounts();
            Vector4    svgSubRectMinMax = Vector4.zero;

            if (isSubRect)
            {
                if (svgSubRect.width <= 0 || svgSubRect.height <= 0)
                {
                    finalVertexCount = finalIndexCount = 0;
                    s_VectorGraphicsStretch.End();
                    return; // Totally clipped
                }
                svgSubRectMinMax = new Vector4(svgSubRect.xMin, svgSubRect.yMin, svgSubRect.xMax, svgSubRect.yMax);
                cc = UpperBoundApproximateRectClippingResults(svgVertices, svgIndices, svgSubRectMinMax);

                // We never kill vertices, just triangles.. so the clipper will only cause growth in the vertex count
                newVertexCount += cc.clippedTriangles * 6;    // 6 new vertices per clipped triangle
                newIndexCount  += cc.addedTriangles * 3;
                newIndexCount  -= cc.degenerateTriangles * 3; // We will not add the indices of degenerate triangles, so discount them
            }

            var mwd = meshAlloc.alloc((uint)newVertexCount, (uint)newIndexCount, ref meshAlloc);

            // Copy indices straight. If clipping is involved, perform clipping. This will fill all the indices
            // as well as register some new vertices at the end of the original set of vertices
            if (isSubRect)
            {
                RectClip(svgVertices, svgIndices, svgSubRectMinMax, mwd, cc, ref newVertexCount);
            }
            else
            {
                mwd.SetAllIndices(svgIndices);
            }

            // Transform all original vertices, vertices generated by clipping will use those directly
            var uvRegion   = mwd.uvRegion;
            int vertsCount = svgVertices.Length;

            for (int i = 0; i < vertsCount; i++)
            {
                var v = svgVertices[i];
                v.position.x = v.position.x * posScale.x + posOffset.x;
                v.position.y = v.position.y * posScale.y + posOffset.y;
                v.uv.x       = v.uv.x * uvRegion.width + uvRegion.xMin;
                v.uv.y       = v.uv.y * uvRegion.height + uvRegion.yMin;
                v.tint      *= tint;
                uint settingIndex = (uint)(((v.opacityPageSVGSettingIndex.b << 8) | v.opacityPageSVGSettingIndex.a) + settingIndexOffset);
                v.opacityPageSVGSettingIndex.b = (byte)(settingIndex >> 8);
                v.opacityPageSVGSettingIndex.a = (byte)settingIndex;
                mwd.SetNextVertex(v);
            }

            // Transform newely generated vertices as well (if any)
            for (int i = vertsCount; i < newVertexCount; i++)
            {
                var v = mwd.m_Vertices[i];
                v.position.x = v.position.x * posScale.x + posOffset.x;
                v.position.y = v.position.y * posScale.y + posOffset.y;
                v.uv.x       = v.uv.x * uvRegion.width + uvRegion.xMin;
                v.uv.y       = v.uv.y * uvRegion.height + uvRegion.yMin;
                v.tint      *= tint;
                uint settingIndex = (uint)(((v.opacityPageSVGSettingIndex.b << 8) | v.opacityPageSVGSettingIndex.a) + settingIndexOffset);
                v.opacityPageSVGSettingIndex.b = (byte)(settingIndex >> 8);
                v.opacityPageSVGSettingIndex.a = (byte)settingIndex;
                mwd.m_Vertices[i] = v;
            }

            finalVertexCount = mwd.vertexCount;
            finalIndexCount  = mwd.indexCount;

            s_VectorGraphicsStretch.End();
        }