Index: Src/Packages/Drawing/VGL/Inc/NsDrawing/VGLTextLayout.h
===================================================================
--- Src/Packages/Drawing/VGL/Inc/NsDrawing/VGLTextLayout.h	(revision 17620)
+++ Src/Packages/Drawing/VGL/Inc/NsDrawing/VGLTextLayout.h	(working copy)
@@ -313,6 +313,10 @@
     /// Unserializes from the specified memory buffer
     void Unserialize(const char* buffer);
 
+#if NS_TEXT_SHAPING
+    const Vector<GlyphRun, 1>& kfeGetRuns() const { return mRuns; }
+#endif
+
     /// Cleanup operations on internal resources
     static void Finalize();
 
Index: Src/Packages/Drawing/VGL/Src/ShapingFull.h
===================================================================
--- Src/Packages/Drawing/VGL/Src/ShapingFull.h	(revision 17620)
+++ Src/Packages/Drawing/VGL/Src/ShapingFull.h	(working copy)
@@ -1250,7 +1250,10 @@
     float& x, float& y)
 {
     // This function expect a grapheme index, not a character index
-    NS_ASSERT(grapheme < layout->mNumGraphemes);
+    if (!(grapheme < layout->mNumGraphemes))
+    {
+        return;
+    }
 
     // Glyphs -> Display ordering
     // ShapingGlyphs -> Logical ordering
Index: Src/Packages/Gui/Core/Include/NsGui/FormattedText.h
===================================================================
--- Src/Packages/Gui/Core/Include/NsGui/FormattedText.h	(revision 17620)
+++ Src/Packages/Gui/Core/Include/NsGui/FormattedText.h	(working copy)
@@ -56,6 +56,18 @@
     float baseline;
 };
 
+////////////////////////////////////////////////////////////////////////////////////////////////////
+#if NS_TEXT_SHAPING
+struct kfeRunInfo
+{
+    float left;
+    float width;
+
+    float center() const { return left + width * 0.5f; }
+    float right() const { return left + width; }
+};
+#endif
+
 NS_WARNING_PUSH
 NS_MSVC_WARNING_DISABLE(4251 4275)
 
@@ -164,6 +176,10 @@
     bool IsInitialized() const;
     void Init();
 
+#if NS_TEXT_SHAPING
+    Vector<kfeRunInfo> kfeComputeRunInfos() const;
+#endif
+
     NS_IMPLEMENT_INTERFACE_FIXUP
 
 private:
Index: Src/Packages/Gui/Core/Src/FormattedText.cpp
===================================================================
--- Src/Packages/Gui/Core/Src/FormattedText.cpp	(revision 17620)
+++ Src/Packages/Gui/Core/Src/FormattedText.cpp	(working copy)
@@ -997,7 +997,30 @@
     return brushIndex == -1 || mBrushes[brushIndex]->IsTransparent();
 }
 
+#if NS_TEXT_SHAPING
+
 ////////////////////////////////////////////////////////////////////////////////////////////////////
+Vector<kfeRunInfo> FormattedText::kfeComputeRunInfos() const
+{
+    Vector<kfeRunInfo> output;
+
+    const Vector<GlyphRun, 1>& glyphRuns = mTextLayout->kfeGetRuns();
+    output.Reserve(glyphRuns.Size());
+    for (const GlyphRun& glyphRun : glyphRuns)
+    {
+        float left, right, y;
+        mTextLayout->HitTestTextPosition(glyphRun.firstRenderGlyph, false, left, y);
+        mTextLayout->HitTestTextPosition(glyphRun.firstRenderGlyph + glyphRun.numRenderGlyphs - 1, true, right, y);
+
+        output.EmplaceBack(kfeRunInfo{ left, right - left });
+    }
+
+    return output;
+}
+
+#endif
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
 NS_BEGIN_COLD_REGION
 
 NS_IMPLEMENT_REFLECTION(FormattedText)
Index: Src/Packages/Gui/Core/Src/TextBlock.cpp
===================================================================
--- Src/Packages/Gui/Core/Src/TextBlock.cpp	(revision 17620)
+++ Src/Packages/Gui/Core/Src/TextBlock.cpp	(working copy)
@@ -20,8 +20,10 @@
 #include <NsGui/DrawingContext.h>
 #include <NsGui/FormattedText.h>
 #include <NsGui/RectangleGeometry.h>
+#include <NsGui/SolidColorBrush.h>
 #include <NsGui/MatrixTransform.h>
 #include <NsGui/Typography.h>
+#include <NsGui/Pen.h>
 #include <NsCore/UTF8.h>
 #include <NsCore/String.h>
 #include <NsCore/ReflectionImplement.h>
@@ -31,6 +33,7 @@
 
 #include "LayoutFlags.h"
 
+Noesis::Ptr<Noesis::Pen> pen;
 
 #undef DrawText
 
@@ -42,6 +45,7 @@
 #include <NsCore/HashMap.h>
 static HashSet<TextBlock*> gRegisteredTexts;
 #endif
+#include <NsGui/Brushes.h>
 
 ////////////////////////////////////////////////////////////////////////////////////////////////////
 enum TextFlags
@@ -75,6 +79,11 @@
 
     gRegisteredTexts.Insert(this);
   #endif
+
+
+    pen = Noesis::MakePtr<Noesis::Pen>();
+    pen->SetBrush(Noesis::Brushes::Black());
+    pen->SetThickness(1);
 }
 
 ////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -97,6 +106,11 @@
 
     gRegisteredTexts.Insert(this);
   #endif
+
+
+    pen = Noesis::MakePtr<Noesis::Pen>();
+    pen->SetBrush(Noesis::Brushes::Black());
+    pen->SetThickness(1);
 }
 
 ////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -701,6 +715,21 @@
         }
 
         const Thickness& padding = GetPadding();
+
+
+        int i = 0;
+        auto boup = mFormattedText->kfeComputeRunInfos();
+        for (auto kfe_run_info : boup)
+        {
+            context->DrawRectangle(
+                kfe_run_info.width >= 5.0f ? (i % 2 == 0 ? Noesis::Brushes::Red() : Noesis::Brushes::Green()) : Noesis::Brushes::Blue(),
+                pen,
+                Noesis::Rect(Noesis::Point(padding.left, padding.top) + Noesis::Point(kfe_run_info.left, kfe_run_info.width >= 5.0f ? 0 : 10.0f), Noesis::Size(Noesis::Max(kfe_run_info.width, 5.0f), textSize.height)));
+            i++;
+        }
+
+
+
         context->DrawText(mFormattedText, Point(padding.left, padding.top));
 
         if (NS_UNLIKELY(rtl))
