Spracherkennung für: .glsl vermutete Sprache: Unknown {[0] [0] [0]} [Methode: Schwerpunktbildung, einfache Gewichte, sechs Dimensionen]
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v.
2.
0. If a copy of the MPL was not distributed with this
* file, You can obtain one at
http://mozilla.org/MPL/2.
0/. */
#include shared,prim_shared,gpu_buffer
flat varying mediump vec4 v_color;
flat varying mediump vec3 v_mask_swizzle;
// Normalized bounds of the source image in the texture.
flat varying highp vec4 v_uv_bounds;
// Interpolated UV coordinates to sample.
varying highp vec2 v_uv;
#if defined(WR_FEATURE_GLYPH_TRANSFORM) && !defined(SWGL_CLIP_DIST)
varying highp vec4 v_uv_clip;
#endif
#ifdef WR_VERTEX_SHADER
#define VECS_PER_TEXT_RUN
1
#define GLYPHS_PER_GPU_BLOCK
2U
#ifdef WR_FEATURE_GLYPH_TRANSFORM
bool rect_inside_rect(RectWithEndpoint little, RectWithEndpoint big) {
return all(lessThanEqual(vec4(big.p0, little.p1), vec4(little.p0, big.p1)));
}
#endif //WR_FEATURE_GLYPH_TRANSFORM
struct Glyph {
vec2 offset;
};
Glyph fetch_glyph(int specific_prim_address,
int glyph_index) {
// Two glyphs are packed in each texel in the GPU cache.
int glyph_address = specific_prim_address +
VECS_PER_TEXT_RUN +
int(uint(glyph_index) / GLYPHS_PER_GPU_BLOCK);
vec4 data = fetch_from_gpu_buffer_1f(glyph_address);
// Select XY or ZW based on glyph index.
vec2 glyph = mix(data.xy, data.zw,
bvec2(uint(glyph_index) % GLYPHS_PER_GPU_BLOCK ==
1U));
return Glyph(glyph);
}
struct GlyphResource {
vec4 uv_rect;
vec2 offset;
float scale;
};
GlyphResource fetch_glyph_resource(int address) {
vec4 data[
2] = fetch_from_gpu_buffer_2f(address);
return GlyphResource(data[
0], data[
1].xy, data[
1].z);
}
struct TextRun {
vec4 color;
};
TextRun fetch_text_run(int address) {
vec4 data = fetch_from_gpu_buffer_1f(address);
return TextRun(data);
}
void main() {
Instance instance = decode_instance_attributes();
PrimitiveHeader ph = fetch_prim_header(instance.prim_header_address);
Transform transform = fetch_transform(ph.transform_id);
ClipArea clip_area = fetch_clip_area(instance.clip_address);
PictureTask task = fetch_picture_task(ph.picture_task_address);
int glyph_index = instance.segment_index;
int color_mode = instance.flags &
0xF;
int subpx_offset_x = (instance.flags >>
4) &
0x3;
int subpx_offset_y = (instance.flags >>
6) &
0x3;
int subpx_dir = (instance.flags >>
8) &
0x3;
int is_packed_glyph = (instance.flags >>
10) &
0x1;
TextRun text = fetch_text_run(ph.specific_prim_address);
// Per-glyph device-space offset: the glyph pen position snapped to the
// device grid on the CPU (`request_resources`), expressed relative to the
// transformed run anchor. No transform or snapping is applied to it here.
Glyph glyph = fetch_glyph(ph.specific_prim_address, glyph_index);
GlyphResource res = fetch_glyph_resource(instance.resource_address);
// For multi-variant glyphs, adjust the UV rect to select the correct quarter
// of the packed texture based on subpixel offset. This must happen before
// geometry calculations since the glyph rect size depends on the UV rect.
if (is_packed_glyph !=
0) {
int variant_index = (subpx_dir == SUBPX_DIR_HORIZONTAL) ? subpx_offset_x : subpx_offset_y
;
float quarter_width = (res.uv_rect.z - res.uv_rect.x) * 0.25;
res.uv_rect.x = res.uv_rect.x + float(variant_index) * quarter_width;
res.uv_rect.z = res.uv_rect.x + quarter_width;
}
// Device-space position of the run anchor (`ph.local_rect.p0`, the prim
// rect origin), via the same prim -> raster transform + device pixel scale
// the rest of the pipeline uses. The CPU computed the per-glyph offsets
// relative to this exact value, so the absolute device positions
// reconstruct here.
vec2 device_anchor = (transform.m * vec4(ph.local_rect.p0, 0.0, 1.0)).xy * task.device_pixel_scale;
float inv_dps = 1.0 / task.device_pixel_scale;
VertexInfo vi;
vec2 f;
#ifdef WR_FEATURE_GLYPH_TRANSFORM
// Device mode, transformed (2D rotated/skewed) glyph. The glyph rect is
// axis-aligned in device (glyph-raster) space; `glyph.offset` is the
// device-grid-snapped pen offset. `write_vertex` clamps to the axis-aligned
// local clip rect, which would shear a rotated quad — so by default build
// the quad from the local-space AABB of the four mapped corners (clamping an
// AABB stays clean) and let `v_uv_clip` mask the rotated glyph within it.
// When the glyph fits entirely inside the clip rect there is nothing to
// clamp, so use the exact rotated corners to avoid the AABB's overdraw.
vec2 device_origin = device_anchor + glyph.offset + res.scale * res.offset;
vec2 device_size = res.scale * (res.uv_rect.zw - res.uv_rect.xy);
vec2 c0 = (transform.inv_m * vec4(device_origin * inv_dps, 0.0, 1.0)).xy;
vec2 c1 = (transform.inv_m * vec4(vec2(device_origin.x + device_size.x, device_origin.y) * inv_dps, 0.0, 1.0)).xy;
vec2 c2 = (transform.inv_m * vec4(vec2(device_origin.x, device_origin.y + device_size.y) * inv_dps, 0.0, 1.0)).xy;
vec2 c3 = (transform.inv_m * vec4((device_origin + device_size) * inv_dps, 0.0, 1.0)).xy;
RectWithEndpoint local_aabb = RectWithEndpoint(min(min(c0, c1), min(c2, c3)), max(max(c0, c1), max(c2, c3)));
vec2 local_pos = mix(local_aabb.p0, local_aabb.p1, aPosition.xy);
if (rect_inside_rect(local_aabb, ph.local_clip_rect)) {
vec2 device_corner = mix(device_origin, device_origin + device_size, aPosition.xy);
local_pos = (transform.inv_m * vec4(device_corner * inv_dps, 0.0, 1.0)).xy;
}
vi = write_vertex(local_pos, ph.local_clip_rect, ph.z, transform, task);
// UV fraction within the glyph rect, in device space from the (possibly
// clip-clamped) vertex, so clipping is handled correctly for rotated glyphs.
vec2 device_clamped = (transform.m * vec4(vi.local_pos, 0.0, 1.0)).xy * task.device_pixel_scale;
f = (device_clamped - device_origin) / device_size;
#else
int raster_mode = ph.user_data.y;
if (raster_mode == 0) {
// Device mode, axis-aligned: the device rect maps to an axis-aligned
// local rect, so the clip clamp is clean — map this vertex's device
// corner straight to local.
vec2 device_origin = device_anchor + glyph.offset + res.scale * res.offset;
vec2 device_size = res.scale * (res.uv_rect.zw - res.uv_rect.xy);
vec2 device_corner = mix(device_origin, device_origin + device_size, aPosition.xy);
vec2 local_pos = (transform.inv_m * vec4(device_corner * inv_dps, 0.0, 1.0)).xy;
vi = write_vertex(local_pos, ph.local_clip_rect, ph.z, transform, task);
vec2 device_clamped = (transform.m * vec4(vi.local_pos, 0.0, 1.0)).xy * task.device_pixel_scale;
f = (device_clamped - device_origin) / device_size;
} else {
// Local-raster mode: the glyph was rasterized at `raster_scale` with an
// identity transform. Position and scale it in local space — mapping the
// raster-space glyph rect to local by `glyph_scale_inv` — and let
// `write_vertex` apply the (possibly animated / scaling / perspective)
// transform. No device snapping happens here (it was done in raster space
// on the CPU) so glyphs don't wiggle under animation. `glyph.offset` is
// the absolute snapped raster-space position of the glyph pen.
float raster_scale = float(ph.user_data.x) / 65535.0;
float glyph_raster_scale = raster_scale * task.device_pixel_scale;
float glyph_scale_inv = res.scale / glyph_raster_scale;
vec2 glyph_origin = glyph_scale_inv * (res.offset + glyph.offset / res.scale);
RectWithEndpoint glyph_rect = RectWithEndpoint(
glyph_origin,
glyph_origin + glyph_scale_inv * (res.uv_rect.zw - res.uv_rect.xy)
);
vec2 local_pos = mix(glyph_rect.p0, glyph_rect.p1, aPosition.xy);
vi = write_vertex(local_pos, ph.local_clip_rect, ph.z, transform, task);
f = (vi.local_pos - glyph_rect.p0) / rect_size(glyph_rect);
}
#endif
#ifdef WR_FEATURE_GLYPH_TRANSFORM
// For transformed glyphs the local clip rect is axis-aligned but the glyph
// quad is rotated, so `write_vertex`'s clamp can pull a corner off the glyph.
// Clip in glyph space instead: discard fragments outside [0,1] of the rect.
#ifdef SWGL_CLIP_DIST
gl_ClipDistance[0] = f.x;
gl_ClipDistance[1] = f.y;
gl_ClipDistance[2] = 1.0 - f.x;
gl_ClipDistance[3] = 1.0 - f.y;
#else
v_uv_clip = vec4(f, 1.0 - f);
#endif
#endif
write_clip(vi.world_pos, clip_area, task);
switch (color_mode) {
case COLOR_MODE_ALPHA:
v_mask_swizzle = vec3(0.0, 1.0, 1.0);
v_color = text.color;
break;
case COLOR_MODE_BITMAP_SHADOW:
#ifdef SWGL_BLEND
swgl_blendDropShadow(text.color);
v_mask_swizzle = vec3(1.0, 0.0, 0.0);
v_color = vec4(1.0);
#else
v_mask_swizzle = vec3(0.0, 1.0, 0.0);
v_color = text.color;
#endif
break;
case COLOR_MODE_COLOR_BITMAP:
v_mask_swizzle = vec3(1.0, 0.0, 0.0);
v_color = vec4(text.color.a);
break;
case COLOR_MODE_SUBPX_DUAL_SOURCE:
#ifdef SWGL_BLEND
swgl_blendSubpixelText(text.color);
v_mask_swizzle = vec3(1.0, 0.0, 0.0);
v_color = vec4(1.0);
#else
v_mask_swizzle = vec3(text.color.a, 0.0, 0.0);
v_color = text.color;
#endif
break;
default:
v_mask_swizzle = vec3(0.0, 0.0, 0.0);
v_color = vec4(1.0);
}
vec2 texture_size = vec2(TEX_SIZE(sColor0));
vec2 st0 = res.uv_rect.xy / texture_size;
vec2 st1 = res.uv_rect.zw / texture_size;
v_uv = mix(st0, st1, f);
v_uv_bounds = (res.uv_rect + vec4(0.5, 0.5, -0.5, -0.5)) / texture_size.xyxy;
}
#endif // WR_VERTEX_SHADER
#ifdef WR_FRAGMENT_SHADER
Fragment text_fs(void) {
Fragment frag;
vec2 tc = clamp(v_uv, v_uv_bounds.xy, v_uv_bounds.zw);
vec4 mask = texture(sColor0, tc);
// v_mask_swizzle.z != 0 means we are using an R8 texture as alpha,
// and therefore must swizzle from the r channel to all channels.
mask = mix(mask, mask.rrrr, bvec4(v_mask_swizzle.z != 0.0));
#ifndef WR_FEATURE_DUAL_SOURCE_BLENDING
mask.rgb = mask.rgb * v_mask_swizzle.x + mask.aaa * v_mask_swizzle.y;
#endif
#if defined(WR_FEATURE_GLYPH_TRANSFORM) && !defined(SWGL_CLIP_DIST)
mask *= float(all(greaterThanEqual(v_uv_clip, vec4(0.0))));
#endif
frag.color = v_color * mask;
#if defined(WR_FEATURE_DUAL_SOURCE_BLENDING) && !defined(SWGL_BLEND)
frag.blend = mask * v_mask_swizzle.x + mask.aaaa * v_mask_swizzle.y;
#endif
return frag;
}
void main() {
Fragment frag = text_fs();
float clip_mask = do_clip();
frag.color *= clip_mask;
#if defined(WR_FEATURE_DEBUG_OVERDRAW)
oFragColor = WR_DEBUG_OVERDRAW_COLOR;
#elif defined(WR_FEATURE_DUAL_SOURCE_BLENDING) && !defined(SWGL_BLEND)
oFragColor = frag.color;
oFragBlend = frag.blend * clip_mask;
#else
write_output(frag.color);
#endif
}
#if defined(SWGL_DRAW_SPAN) && defined(SWGL_BLEND) && defined(SWGL_CLIP_DIST)
void swgl_drawSpanRGBA8() {
// Only support simple swizzles for now. More complex swizzles must either
// be handled by blend overrides or the slow path.
if (v_mask_swizzle.x != 0.0 && v_mask_swizzle.x != 1.0) {
return;
}
#ifdef WR_FEATURE_DUAL_SOURCE_BLENDING
swgl_commitTextureLinearRGBA8(sColor0, v_uv, v_uv_bounds);
#else
if (swgl_isTextureR8(sColor0)) {
swgl_commitTextureLinearColorR8ToRGBA8(sColor0, v_uv, v_uv_bounds, v_color);
} else {
swgl_commitTextureLinearColorRGBA8(sColor0, v_uv, v_uv_bounds, v_color);
}
#endif
}
#endif
#endif // WR_FRAGMENT_SHADER