Skip to content
This repository has been archived by the owner on Apr 20, 2023. It is now read-only.

Commit

Permalink
Fix the fuzzy antialiasing artifacts around the edges of the rendered…
Browse files Browse the repository at this point in the history
… background/border boxes. The coordinates for each shape are doubled, the coordinate system is halved, and the coordinate origin is shifted by 1; this makes vertical/horizontal lines lie directly along a pixel rather than halfway in between, eliminating the antialiasing artifacts.
  • Loading branch information
Jason Johnston committed Apr 30, 2010
1 parent e03ede9 commit 66de37a
Show file tree
Hide file tree
Showing 3 changed files with 110 additions and 45 deletions.
67 changes: 37 additions & 30 deletions sources/BackgroundAndBorderRenderer.js
Original file line number Diff line number Diff line change
Expand Up @@ -66,8 +66,9 @@ PIE.BackgroundAndBorderRenderer = (function() {
w = el.offsetWidth;
h = el.offsetHeight;
shape.stroked = false;
shape.coordsize = w + ',' + h;
shape.path = this.getBoxPath();
shape.coordsize = w * 2 + ',' + h * 2;
shape.coordorigin = '1,1';
shape.path = this.getBoxPath( null, 2 );
s = shape.style;
s.width = w;
s.height = h;
Expand Down Expand Up @@ -105,8 +106,9 @@ PIE.BackgroundAndBorderRenderer = (function() {
shape.stroked = false;
shape.fill.type = 'tile';
shape.fillcolor = 'none';
shape.coordsize = w + ',' + h;
shape.path = this.getBoxPath();
shape.coordsize = w * 2 + ',' + h * 2;
shape.coordorigin = '1,1';
shape.path = this.getBoxPath( 0, 2 );
s = shape.style;
s.width = w;
s.height = h;
Expand Down Expand Up @@ -153,19 +155,21 @@ PIE.BackgroundAndBorderRenderer = (function() {
clipT = 0, clipR = elW, clipB = elH, clipL = 0;

// Positioning - find the pixel offset from the top/left and convert to a ratio
pxX = bgPos.x + bwL;
pxY = bgPos.y + bwT;
// The position is shifted by half a pixel, to adjust for the half-pixel coordorigin shift which is
// needed to fix antialiasing but makes the bg image fuzzy.
pxX = bgPos.x + bwL + 0.5;
pxY = bgPos.y + bwT + 0.5;
fill.position = ( pxX / elW ) + ',' + ( pxY / elH );

// Repeating - clip the image shape
if( repeat && repeat !== 'repeat' ) {
if( repeat === 'repeat-x' || repeat === 'no-repeat' ) {
clipT = pxY;
clipB = pxY + size.h;
clipT = pxY + 1;
clipB = pxY + size.h + 1;
}
if( repeat === 'repeat-y' || repeat === 'no-repeat' ) {
clipL = pxX;
clipR = pxX + size.w;
clipL = pxX + 1;
clipR = pxX + size.w + 1;
}
shape.style.clip = 'rect(' + clipT + 'px,' + clipR + 'px,' + clipB + 'px,' + clipL + 'px)';
}
Expand Down Expand Up @@ -378,11 +382,12 @@ PIE.BackgroundAndBorderRenderer = (function() {
if( props ) {
this.hideBorder();

segments = this.getBorderSegments();
segments = this.getBorderSegments( 2 );
for( i = 0, len = segments.length; i < len; i++) {
seg = segments[i];
shape = this.getShape( 'borderPiece' + i, seg.stroke ? 'stroke' : 'fill', 3 );
shape.coordsize = w + ',' + h;
shape.coordsize = w * 2 + ',' + h * 2;
shape.coordorigin = '1,1';
shape.path = seg.path;
s = shape.style;
s.width = w;
Expand Down Expand Up @@ -449,9 +454,10 @@ PIE.BackgroundAndBorderRenderer = (function() {

/**
* Get the VML path definitions for the border segment(s).
* @param {number=} mult If specified, all coordinates will be multiplied by this number
* @return {Array.<string>}
*/
getBorderSegments: function() {
getBorderSegments: function( mult ) {
var el = this.element,
elW, elH,
borderInfo = this.styleInfos.borderInfo,
Expand All @@ -468,18 +474,19 @@ PIE.BackgroundAndBorderRenderer = (function() {

if( borderProps.widthsSame && borderProps.stylesSame && borderProps.colorsSame ) {
// shortcut for identical border on all sides - only need 1 stroked shape
wT = widths['t'].pixels( el );
wR = Math.floor( wT / 2 );
wT = widths['t'].pixels( el ); //thickness
wR = wT / 2; //shrink
segments.push( {
path: this.getBoxPath( { t: wR, r: wR, b: wR, l: wR } ),
path: this.getBoxPath( { t: wR, r: wR, b: wR, l: wR }, mult ),
stroke: styles['t'],
color: colors['t'],
weight: wT
} );
}
else {
elW = el.offsetWidth - 1;
elH = el.offsetHeight - 1;
mult = mult || 1;
elW = el.offsetWidth;
elH = el.offsetHeight;

wT = widths['t'].pixels( el );
wR = widths['r'].pixels( el );
Expand Down Expand Up @@ -507,10 +514,10 @@ PIE.BackgroundAndBorderRenderer = (function() {
isRight = corner.charAt( 1 ) === 'r',
isBottom = corner.charAt( 0 ) === 'b';
return ( rx > 0 && ry > 0 ) ?
( isRight ? ceil( elW - rx ) : floor( rx ) ) + ',' + // center x
( isBottom ? ceil( elH - ry ) : floor( ry ) ) + ',' + // center y
( floor( rx ) - shrinkX ) + ',' + // width
( floor( ry ) - shrinkY ) + ',' + // height
( isRight ? ceil( elW - rx ) : floor( rx ) ) * mult + ',' + // center x
( isBottom ? ceil( elH - ry ) : floor( ry ) ) * mult + ',' + // center y
( floor( rx ) - shrinkX ) * mult + ',' + // width
( floor( ry ) - shrinkY ) * mult + ',' + // height
( startAngle * deg ) + ',' + // start angle
( 45 * deg * ( ccw ? 1 : -1 ) ) // angle change
: '';
Expand All @@ -536,17 +543,17 @@ PIE.BackgroundAndBorderRenderer = (function() {
segments.push( {
path: (
side === 't' ?
'm' + floor( radii.x['tl'] ) + ',' + ceil( wT/2 ) +
'l' + ceil( elW - radii.x['tr'] ) + ',' + ceil( wT/2 ) :
'm' + floor( radii.x['tl'] ) * mult + ',' + ceil( wT/2 ) * mult +
'l' + ceil( elW - radii.x['tr'] ) * mult + ',' + ceil( wT/2 ) * mult :
side === 'r' ?
'm' + ceil( elW - wR/2 ) + ',' + floor( radii.y['tr'] ) +
'l' + ceil( elW - wR/2 ) + ',' + ceil( elH - radii.y['br'] ) :
'm' + ceil( elW - wR/2 ) * mult + ',' + floor( radii.y['tr'] ) * mult +
'l' + ceil( elW - wR/2 ) * mult + ',' + ceil( elH - radii.y['br'] ) * mult :
side === 'b' ?
'm' + ceil( elW - radii.x['br'] ) + ',' + floor( elH - wB/2 ) +
'l' + floor( radii.x['bl'] ) + ',' + floor( elH - wB/2 ) :
'm' + ceil( elW - radii.x['br'] ) * mult + ',' + floor( elH - wB/2 ) * mult +
'l' + floor( radii.x['bl'] ) * mult + ',' + floor( elH - wB/2 ) * mult :
// side === 'l'
'm' + floor( wL/2 ) + ',' + ceil( elH - radii.y['bl'] ) +
'l' + floor( wL/2 ) + ',' + floor( radii.y['tl'] )
'm' + floor( wL/2 ) * mult + ',' + ceil( elH - radii.y['bl'] ) * mult +
'l' + floor( wL/2 ) * mult + ',' + floor( radii.y['tl'] ) * mult
),
stroke: styles[ side ],
weight: pxWidths[ side ],
Expand Down
33 changes: 18 additions & 15 deletions sources/RendererBase.js
Original file line number Diff line number Diff line change
Expand Up @@ -191,32 +191,35 @@ PIE.RendererBase = {
* Return the VML path string for the element's background box, with corners rounded.
* @param {Object.<{t:number, r:number, b:number, l:number}>} shrink - if present, specifies number of
* pixels to shrink the box path inward from the element's four sides.
* @param {number=} mult If specified, all coordinates will be multiplied by this number
* @return {string} the VML path
*/
getBoxPath: function( shrink ) {
getBoxPath: function( shrink, mult ) {
mult = mult || 1;

var r, str,
el = this.element,
w = el.offsetWidth - 1,
h = el.offsetHeight - 1,
w = el.offsetWidth * mult,
h = el.offsetHeight * mult,
radInfo = this.styleInfos.borderRadiusInfo,
floor = Math.floor, ceil = Math.ceil,
shrinkT = shrink ? shrink.t : 0,
shrinkR = shrink ? shrink.r : 0,
shrinkB = shrink ? shrink.b : 0,
shrinkL = shrink ? shrink.l : 0,
shrinkT = shrink ? shrink.t * mult : 0,
shrinkR = shrink ? shrink.r * mult : 0,
shrinkB = shrink ? shrink.b * mult : 0,
shrinkL = shrink ? shrink.l * mult : 0,
tlX, tlY, trX, trY, brX, brY, blX, blY;

if( radInfo.isActive() ) {
r = this.getRadiiPixels( radInfo.getProps() );

tlX = r.x['tl'];
tlY = r.y['tl'];
trX = r.x['tr'];
trY = r.y['tr'];
brX = r.x['br'];
brY = r.y['br'];
blX = r.x['bl'];
blY = r.y['bl'];
tlX = r.x['tl'] * mult;
tlY = r.y['tl'] * mult;
trX = r.x['tr'] * mult;
trY = r.y['tr'] * mult;
brX = r.x['br'] * mult;
brY = r.y['br'] * mult;
blX = r.x['bl'] * mult;
blY = r.y['bl'] * mult;

str = 'm' + shrinkL + ',' + floor(tlY) +
'qy' + floor(tlX) + ',' + shrinkT +
Expand Down
55 changes: 55 additions & 0 deletions tests/sizing-tests.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
<!DOCTYPE html>

<html>
<head>
<title>Tests that VML boxes are sized exactly as the main element</title>

<style>

body {
/*background:url(border.png);*/
}

.test {
behavior: url(../build/PIE_uncompressed.htc);
position: relative;
border-radius: 1em;
margin: 0 0 2em;
}
.control {
background: #FF0000;
position: absolute;
}

#test1,
#control1 {
width: 200px;
height: 201px;
}
#test1 {
background: green;
-pie-background: green;
}

#test2,
#control2 {
width: 200px;
height: 100px;
}
#test2 {
-pie-background: url(background2.gif);
}



</style>
</head>
<body>

<div id="control1" class="control">test 1</div>
<div id="test1" class="test">test 1</div>

<div id="control2" class="control">test 1</div>
<div id="test2" class="test">test 1</div>
</body>
</html>

0 comments on commit 66de37a

Please sign in to comment.