Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Huge improvement to box-shadow rendering performance and accuracy! No…

… longer uses any Blur filter, instead it now uses a radial gradient from opaque to transparent with the undocumented 'gradienttitle' fill type so it follows the rounded box shape. There is no longer any lag with initial rendering, updating size, or scrolling the page. It also gives better control over the size of the blur gradient so it more accurately matches the blur metrics of other browsers in most cases.
  • Loading branch information...
commit 0479609e8adc5a8cb7571e1d8750406629999809 1 parent 063dfde
Jason Johnston authored
Showing with 45 additions and 26 deletions.
  1. +40 −23 sources/BoxShadowOutsetRenderer.js
  2. +5 −3 sources/RendererBase.js
View
63 sources/BoxShadowOutsetRenderer.js
@@ -24,55 +24,72 @@ PIE.BoxShadowOutsetRenderer = PIE.RendererBase.newRenderer( {
if( this.isActive() ) {
var el = this.element,
shadowInfos = this.styleInfos.boxShadowInfo.getProps().outset,
- i = shadowInfos.length,
+ i = shadowInfos.length, j,
w = el.offsetWidth,
h = el.offsetHeight,
- shadowInfo, shape, ss, xOff, yOff, spread, blur, shrink, halfBlur, filter, alpha;
+ corners = [ 'tl', 'tr', 'br', 'bl' ], corner,
+ shadowInfo, radii, shape, fill, ss, xOff, yOff, spread, blur, shrink, alpha,
+ gradientLength, focusX, focusY;
while( i-- ) {
shadowInfo = shadowInfos[ i ];
shape = this.getShape( 'shadow' + i, 'fill', this.getBox() );
ss = shape.style;
+ fill = shape.fill;
xOff = shadowInfo.xOffset.pixels( el );
yOff = shadowInfo.yOffset.pixels( el );
spread = shadowInfo.spread.pixels( el ),
blur = shadowInfo.blur.pixels( el );
- // Adjust the blur value so it's always an even number
- halfBlur = Math.ceil( blur / 2 );
- blur = halfBlur * 2;
-
- // Apply blur filter to the shape. Applying the blur filter twice with
- // half the pixel value gives a shadow nearly identical to other browsers.
- if( blur > 0 ) {
- filter = 'progid:DXImageTransform.Microsoft.blur(pixelRadius=' + halfBlur + ')';
- ss.filter = filter + ' ' + filter;
- }
-
// Position and size
- ss.left = xOff - blur;
- ss.top = yOff - blur;
+ ss.left = xOff;
+ ss.top = yOff;
ss.width = w;
ss.height = h;
+ shape.coordsize = w * 2 + ',' + h * 2;
+ //shape.coordorigin = '1,1';
// Color and opacity
shape.stroked = false;
shape.filled = true;
- shape.fillcolor = shadowInfo.color.value( el );
-
+ fill.color = shadowInfo.color.value( el );
alpha = shadowInfo.color.alpha();
if( alpha < 1 ) {
- shape.fill.opacity = alpha;
+ ss.filter = 'alpha(opacity=' + ( alpha * 100 ) + ')';
}
- // Blurred shadows end up slightly too wide; shrink them down
- shrink = blur > 0 ? 4 : 0,
- shape.coordsize = ( w * 2 + shrink ) + ',' + ( h * 2 + shrink );
+ if( blur ) {
+ fill['type'] = 'gradienttitle'; //makes the VML gradient follow the shape's outline - hooray for undocumented features?!?!
+ fill['color2'] = fill.color;
+ fill['opacity'] = 0;
+
+ gradientLength = blur * 2;
+ var diff = Math.max( gradientLength - w / 2, gradientLength - h / 2 );
+ if( diff > 0 ) {
+ gradientLength -= diff;
+ }
+
+ focusX = gradientLength / ( w + spread + blur );
+ focusY = gradientLength / ( h + spread + blur );
+ fill['focusposition'] = focusX + ',' + focusY;
+ fill['focussize'] = ( 1 - focusX * 2 ) + ',' + ( 1 - focusY * 2 );
+
+ // Modify square corners to round them slightly if blurred
+ radii = this.styleInfos.borderRadiusInfo.getProps();
+ if( !radii ) {
+ radii = { x: {}, y: {} };
+ for( j = 4; j--; ) {
+ corner = corners[j];
+ radii.x[ corner ] = radii.y[ corner ] = PIE.Length.ZERO;
+ }
+ }
+ }
- shape.coordorigin = '1,1';
- shape.path = this.getBoxPath( spread ? { t: -spread, r: -spread, b: -spread, l: -spread } : 0, 2 );
+ // Shape path
+ shrink = -spread - blur;
+ shape.path = this.getBoxPath( { t: shrink, r: shrink, b: shrink, l: shrink }, 2, radii );
}
} else {
this.destroy();
View
8 sources/RendererBase.js
@@ -200,9 +200,11 @@ PIE.RendererBase = {
* @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
+ * @param {Object=} radii If specified, this will be used for the corner radii instead of the properties
+ * from this renderer's borderRadiusInfo object.
* @return {string} the VML path
*/
- getBoxPath: function( shrink, mult ) {
+ getBoxPath: function( shrink, mult, radii ) {
mult = mult || 1;
var r, str,
@@ -217,8 +219,8 @@ PIE.RendererBase = {
shrinkL = shrink ? shrink.l * mult : 0,
tlX, tlY, trX, trY, brX, brY, blX, blY;
- if( radInfo.isActive() ) {
- r = this.getRadiiPixels( radInfo.getProps() );
+ if( radii || radInfo.isActive() ) {
+ r = this.getRadiiPixels( radii || radInfo.getProps() );
tlX = r.x['tl'] * mult;
tlY = r.y['tl'] * mult;
Please sign in to comment.
Something went wrong with that request. Please try again.