Skip to content

Commit

Permalink
Merge pull request #2188 from lsalzman/clip-font-transform
Browse files Browse the repository at this point in the history
fix local clipping of transformed glyphs
  • Loading branch information
glennw committed Dec 8, 2017
2 parents 5756b2e + 9c2d281 commit 22f472f
Show file tree
Hide file tree
Showing 5 changed files with 56 additions and 11 deletions.
35 changes: 24 additions & 11 deletions webrender/res/ps_text_run.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,12 @@ flat varying vec4 vUvBorder;
#define MODE_SUBPX_BG_PASS2 6
#define MODE_COLOR_BITMAP 7

VertexInfo write_text_vertex(vec2 local_pos,
VertexInfo write_text_vertex(vec2 clamped_local_pos,
RectWithSize local_clip_rect,
float z,
Layer layer,
PictureTask task,
RectWithSize snap_rect) {
// Clamp to the two local clip rects.
vec2 clamped_local_pos = clamp_rect(clamp_rect(local_pos, local_clip_rect), layer.local_clip_rect);

// Transform the current vertex to world space.
vec4 world_pos = layer.transform * vec4(clamped_local_pos, 0.0, 1.0);

Expand Down Expand Up @@ -75,9 +72,22 @@ void main(void) {
RectWithSize glyph_rect = RectWithSize(res.offset + transform * (text.offset + glyph.offset),
res.uv_rect.zw - res.uv_rect.xy);

// Select the corner of the glyph rect that we are processing.
// Transform it from glyph space into local space.
vec2 local_pos = inverse(transform) * (glyph_rect.p0 + glyph_rect.size * aPosition.xy);
// Transform the glyph rect back to local space.
mat2 inv = inverse(transform);
RectWithSize local_rect = transform_rect(glyph_rect, inv);

// Select the corner of the glyph's local space rect that we are processing.
vec2 local_pos = local_rect.p0 + local_rect.size * aPosition.xy;

// Calculate a combined local clip rect.
RectWithSize local_clip_rect = intersect_rects(prim.local_clip_rect, prim.layer.local_clip_rect);

// If the glyph's local rect would fit inside the local clip rect, then select a corner from
// the device space glyph rect to reduce overdraw of clipped pixels in the fragment shader.
// Otherwise, fall back to clamping the glyph's local rect to the local clip rect.
local_pos = rect_inside_rect(local_rect, local_clip_rect) ?
inv * (glyph_rect.p0 + glyph_rect.size * aPosition.xy) :
clamp_rect(local_pos, local_clip_rect);
#else
// Scale from glyph space to local space.
float scale = res.scale / uDevicePixelRatio;
Expand All @@ -88,6 +98,9 @@ void main(void) {

// Select the corner of the glyph rect that we are processing.
vec2 local_pos = glyph_rect.p0 + glyph_rect.size * aPosition.xy;

// Clamp to the two local clip rects.
local_pos = clamp_rect(clamp_rect(local_pos, prim.local_clip_rect), prim.layer.local_clip_rect);
#endif

VertexInfo vi = write_text_vertex(local_pos,
Expand Down Expand Up @@ -131,16 +144,16 @@ void main(void) {
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;
vUvBorder = (res.uv_rect + vec4(0.499, 0.499, -0.499, -0.499)) / 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);
vec4 mask = texture(sColor0, vUv);

float alpha = do_clip();
float alpha = float(all(lessThanEqual(vec4(vUvBorder.xy, vUv.xy), vec4(vUv.xy, vUvBorder.zw))));
alpha *= do_clip();

#ifdef WR_FEATURE_SUBPX_BG_PASS1
mask.rgb = vec3(mask.a) - mask.rgb;
Expand Down
19 changes: 19 additions & 0 deletions webrender/res/rect.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -27,3 +27,22 @@ RectWithSize to_rect_with_size(RectWithEndpoint rect) {

return result;
}

RectWithSize transform_rect(RectWithSize rect, mat2 transform) {
vec2 center = transform * (rect.p0 + rect.size * 0.5);
vec2 radius = mat2(abs(transform[0]), abs(transform[1])) * (rect.size * 0.5);
return RectWithSize(center - radius, radius * 2.0);
}

RectWithSize intersect_rects(RectWithSize a, RectWithSize b) {
RectWithSize result;
result.p0 = max(a.p0, b.p0);
result.size = min(a.p0 + a.size, b.p0 + b.size) - result.p0;

return result;
}

bool rect_inside_rect(RectWithSize little, RectWithSize big) {
return all(lessThanEqual(vec4(big.p0, little.p0 + little.size),
vec4(little.p0, big.p0 + big.size)));
}
Binary file added wrench/reftests/text/clipped-transform.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
12 changes: 12 additions & 0 deletions wrench/reftests/text/clipped-transform.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
--- # checks that local clip rects don't inappropriately shear transformed glyphs
root:
items:
- type: stacking-context
bounds: [0, 0, 65, 70]
transform: [0.7086478, 0.7055624, 0, 0, -0.7055624, 0.7086478, 0, 0, 0, 0, 1, 0, 40, 10, 0, 1]
items:
- text: "O"
clip-rect: [0, 0, 44, 44]
origin: 0 38
size: 30
font: "FreeSans.ttf"
1 change: 1 addition & 0 deletions wrench/reftests/text/reftest.list
Original file line number Diff line number Diff line change
Expand Up @@ -42,3 +42,4 @@ platform(linux) == subpixel-scale.yaml subpixel-scale.png
platform(linux) == subpixel-skew.yaml subpixel-skew.png
!= shadow-rotate.yaml blank.yaml
platform(linux) == embedded-bitmaps.yaml embedded-bitmaps.png
platform(linux) == clipped-transform.yaml clipped-transform.png

0 comments on commit 22f472f

Please sign in to comment.