 
 #include shared,prim_shared
 
-flat varying vec4 vColor;
-varying vec3 vUv;
-flat varying vec4 vUvBorder;
-flat varying vec2 vMaskSwizzle;
-
-#ifdef WR_FEATURE_GLYPH_TRANSFORM
-varying vec4 vUvClip;
+// A few varying slots for the brushes to use.
+// Using these instead of adding dedicated varyings avoids using a high
+// number of varyings in the multi-brush shader.
+//
+// TODO: This is duplicated from the brush shader code and will be merged
+//       back once text runs use the brush infrastructure.
+flat varying vec4 flat_varying_vec4_0;
+flat varying vec4 flat_varying_vec4_1;
+flat varying vec4 flat_varying_vec4_2;
+varying vec4 varying_vec4_0;
+varying vec4 varying_vec4_1;
+
+#define V_COLOR             flat_varying_vec4_0
+#define V_MASK_SWIZZLE      flat_varying_vec4_1.xy
+// Normalized bounds of the source image in the texture.
+#define V_UV_BOUNDS         flat_varying_vec4_2
+
+// Interpolated UV coordinates to sample.
+#define V_UV                varying_vec4_0.xy
+#define V_LAYER             varying_vec4_0.z
+
+
+#ifdef WR_FEATURE_GLYPH_TRANSFORM
+#define V_UV_CLIP           varying_vec4_1
 #endif
 
 #ifdef WR_VERTEX_SHADER

    switch (color_mode) {
        case COLOR_MODE_ALPHA:
        case COLOR_MODE_BITMAP:
            vMaskSwizzle = vec2(0.0, 1.0);
            vColor = text.color;
            break;
        case COLOR_MODE_SUBPX_BG_PASS2:
        case COLOR_MODE_SUBPX_DUAL_SOURCE:
            vMaskSwizzle = vec2(1.0, 0.0);
            vColor = text.color;
            break;
        case COLOR_MODE_SUBPX_CONST_COLOR:
        case COLOR_MODE_SUBPX_BG_PASS0:
        case COLOR_MODE_COLOR_BITMAP:
            vMaskSwizzle = vec2(1.0, 0.0);
            vColor = vec4(text.color.a);
            break;
        case COLOR_MODE_SUBPX_BG_PASS1:
            vMaskSwizzle = vec2(-1.0, 1.0);
            vColor = vec4(text.color.a) * text.bg_color;
            break;
        default:
            vMaskSwizzle = vec2(0.0);
            vColor = vec4(1.0);
    }

    vec2 texture_size = vec2(textureSize(sColor0, 0));
    vec2 st0 = res.uv_rect.xy / texture_size;
    vec2 st1 = res.uv_rect.zw / texture_size;

    vUv = vec3(mix(st0, st1, f), res.layer);
    vUvBorder = (res.uv_rect + vec4(0.5, 0.5, -0.5, -0.5)) / texture_size.xyxy;
}
#endif

#ifdef WR_FRAGMENT_SHADER
void main(void) {
    vec3 tc = vec3(clamp(vUv.xy, vUvBorder.xy, vUvBorder.zw), vUv.z);
    vec4 mask = texture(sColor0, tc);
    mask.rgb = mask.rgb * vMaskSwizzle.x + mask.aaa * vMaskSwizzle.y;

    float alpha = do_clip();
#ifdef WR_FEATURE_GLYPH_TRANSFORM
    alpha *= float(all(greaterThanEqual(vUvClip, vec4(0.0))));
#endif

#if defined(WR_FEATURE_DEBUG_OVERDRAW)
    oFragColor = WR_DEBUG_OVERDRAW_COLOR;
#elif defined(WR_FEATURE_DUAL_SOURCE_BLENDING)
    vec4 alpha_mask = mask * alpha;
    oFragColor = vColor * alpha_mask;
    oFragBlend = alpha_mask * vColor.a;
#else
    write_output(vColor * mask * alpha);
#endif
}
#endif


#ifdef WR_FEATURE_GLYPH_TRANSFORM
    vec2 f = (glyph_transform * vi.local_pos - glyph_rect.p0) / glyph_rect.size;
    V_UV_CLIP = vec4(f, 1.0 - f);
#else
    vec2 f = (vi.local_pos - glyph_rect.p0) / glyph_rect.size;
#endif
