diff --git a/build.xml b/build.xml index 3261def..0236601 100644 --- a/build.xml +++ b/build.xml @@ -40,6 +40,7 @@ + @@ -84,6 +85,7 @@ + diff --git a/sources/BackgroundRenderer.js b/sources/BackgroundRenderer.js index 506b0a6..a18abad 100644 --- a/sources/BackgroundRenderer.js +++ b/sources/BackgroundRenderer.js @@ -50,7 +50,7 @@ PIE.BackgroundRenderer = PIE.RendererBase.newRenderer( { shape.setSize( bounds.w, bounds.h ); shape.setAttrs( - 'path', this.getBoxPath( 0, 0, 0, 0, 2 ) + 'path', this.getBgClipPath( bounds, props.colorClip ) ); shape.setFillAttrs( 'color', color.colorValue( el ) ); alpha = color.alpha(); @@ -69,7 +69,7 @@ PIE.BackgroundRenderer = PIE.RendererBase.newRenderer( { var props = this.styleInfos.backgroundInfo.getProps(), bounds = this.boundsInfo.getBounds(), images = props && props.bgImages, - img, shape, w, h, s, i; + img, shape, w, h, i; if( images ) { this.hideBackground(); @@ -83,7 +83,7 @@ PIE.BackgroundRenderer = PIE.RendererBase.newRenderer( { shape = this.getShape( 'bgImage' + i, this.shapeZIndex + ( .5 - i / 1000 ) ); shape.setAttrs( - 'path', this.getBoxPath( 0, 0, 0, 0, 2 ) + 'path', this.getBgClipPath( bounds, img.bgClip ) ); shape.setSize( w, h ); @@ -123,9 +123,10 @@ PIE.BackgroundRenderer = PIE.RendererBase.newRenderer( { // It's possible that the element dimensions are zero now but weren't when the original // update executed, make sure that's not the case to avoid divide-by-zero error if( elW && elH ) { - var bgInfo = me.styleInfos.backgroundInfo, + var styleInfos = me.styleInfos, + bgInfo = styleInfos.backgroundInfo, bg = bgInfo.getProps().bgImages[ index ], - bgAreaSize = bgInfo.getBgAreaSize( bg.bgOrigin, me.boundsInfo, me.styleInfos.borderInfo ), + bgAreaSize = bgInfo.getBgAreaSize( bg.bgOrigin, me.boundsInfo, styleInfos.borderInfo, styleInfos.paddingInfo ), adjustedImgSize = ( bg.bgSize || PIE.BgSize.DEFAULT ).pixels( me.targetElement, bgAreaSize.w, bgAreaSize.h, imgSize.w, imgSize.h ), @@ -170,6 +171,48 @@ PIE.BackgroundRenderer = PIE.RendererBase.newRenderer( { }, + /** + * For a given background-clip value, return the VML path for that clip area. + * @param {Object} bounds + * @param {String} bgClip + */ + getBgClipPath: function( bounds, bgClip ) { + var me = this, + shrinkT = 0, + shrinkR = 0, + shrinkB = 0, + shrinkL = 0, + el = me.targetElement, + styleInfos = me.styleInfos, + borders, paddings; + + if ( bgClip && bgClip !== 'border-box' ) { + borders = styleInfos.borderInfo.getProps(); + if ( borders && ( borders = borders.widths ) ) { + shrinkT += borders[ 't' ].pixels( el ); + shrinkR += borders[ 'r' ].pixels( el ); + shrinkB += borders[ 'b' ].pixels( el ); + shrinkL += borders[ 'l' ].pixels( el ); + } + } + + if ( bgClip === 'content-box' ) { + paddings = styleInfos.paddingInfo.getProps(); + if( paddings ) { + shrinkT += paddings[ 't' ].pixels( el ); + shrinkR += paddings[ 'r' ].pixels( el ); + shrinkB += paddings[ 'b' ].pixels( el ); + shrinkL += paddings[ 'l' ].pixels( el ); + } + } + + // Add points at 0,0 and w,h so that the image size/position will still be + // based on the full element area. + return 'm0,0r0,0m' + bounds.w * 2 + ',' + bounds.h * 2 + 'r0,0' + + me.getBoxPath( shrinkT, shrinkR, shrinkB, shrinkL, 2 ); + }, + + /** * For a given background-origin value, return the x/y position of the origin * from the top-left of the element bounds. @@ -178,12 +221,13 @@ PIE.BackgroundRenderer = PIE.RendererBase.newRenderer( { getBgOriginXY: function( bgOrigin ) { var me = this, el = me.targetElement, + styleInfos = me.styleInfos, x = 0, y = 0, - borders, getLength, cs; + borders, paddings; if( bgOrigin !== 'border-box' ) { - borders = me.styleInfos.borderInfo.getProps(); + borders = styleInfos.borderInfo.getProps(); if( borders && ( borders = borders.widths ) ) { x += borders[ 'l' ].pixels( el ); y += borders[ 't' ].pixels( el ); @@ -191,10 +235,11 @@ PIE.BackgroundRenderer = PIE.RendererBase.newRenderer( { } if ( bgOrigin === 'content-box' ) { - getLength = PIE.getLength; - cs = el.currentStyle; - x += getLength( cs.paddingLeft ).pixels( el ); - y += getLength( cs.paddingTop ).pixels( el ); + paddings = styleInfos.paddingInfo.getProps(); + if( paddings ) { + x += paddings[ 'l' ].pixels( el ); + y += paddings[ 't' ].pixels( el ); + } } return { x: x, y: y }; @@ -295,10 +340,12 @@ PIE.BackgroundRenderer = PIE.RendererBase.newRenderer( { // Set opacity; right now we only support this for two-stop gradients, multi-stop // opacity will require chopping up each segment into its own shape. + // Note these seem backwards but they must be that way since VML strangely reverses + // them when the 'colors' property is present. if ( stopCount === 2 ) { shape.setFillAttrs( - 'opacity', stops[0].color.alpha(), - 'o:opacity2', stops[1].color.alpha() + 'opacity', stops[1].color.alpha(), + 'o:opacity2', stops[0].color.alpha() ); } }, diff --git a/sources/BackgroundStyleInfo.js b/sources/BackgroundStyleInfo.js index fbeb724..8eb4955 100644 --- a/sources/BackgroundStyleInfo.js +++ b/sources/BackgroundStyleInfo.js @@ -33,6 +33,7 @@ PIE.BackgroundStyleInfo = PIE.StyleInfoBase.newStyleInfo( { * Format of return object: * { * color: , + * colorClip: <'border-box' | 'padding-box'>, * bgImages: [ * { * imgType: 'image', @@ -226,6 +227,8 @@ PIE.BackgroundStyleInfo = PIE.StyleInfoBase.newStyleInfo( { image.origString = css.substring( beginCharIndex ); props.bgImages.push( image ); } + + props.colorClip = image.bgClip; } // Otherwise, use the standard background properties; let IE give us the values rather than parsing them @@ -360,12 +363,12 @@ PIE.BackgroundStyleInfo = PIE.StyleInfoBase.newStyleInfo( { * @param {PIE.BoundsInfo} boundsInfo * @param {PIE.BorderStyleInfo} borderInfo */ - getBgAreaSize: function( bgOrigin, boundsInfo, borderInfo ) { + getBgAreaSize: function( bgOrigin, boundsInfo, borderInfo, paddingInfo ) { var el = this.targetElement, bounds = boundsInfo.getBounds(), w = bounds.w, h = bounds.h, - borders, getLength, cs; + borders, paddings; if( bgOrigin !== 'border-box' ) { borders = borderInfo.getProps(); @@ -376,10 +379,11 @@ PIE.BackgroundStyleInfo = PIE.StyleInfoBase.newStyleInfo( { } if ( bgOrigin === 'content-box' ) { - getLength = PIE.getLength; - cs = el.currentStyle; - w -= getLength( cs.paddingLeft ).pixels( el ) + getLength( cs.paddingRight ).pixels( el ); - h -= getLength( cs.paddingTop ).pixels( el ) + getLength( cs.paddingBottom ).pixels( el ); + paddings = paddingInfo.getProps(); + if ( paddings ) { + w -= paddings[ 'l' ].pixels( el ) + paddings[ 'l' ].pixels( el ); + h -= paddings[ 't' ].pixels( el ) + paddings[ 'b' ].pixels( el ); + } } return { w: w, h: h }; diff --git a/sources/Element.js b/sources/Element.js index 3cbaa58..836ca75 100644 --- a/sources/Element.js +++ b/sources/Element.js @@ -105,11 +105,14 @@ PIE.Element = (function() { styleInfos = { backgroundInfo: new PIE.BackgroundStyleInfo( el ), borderImageInfo: new PIE.BorderImageStyleInfo( el ), - borderInfo: new PIE.BorderStyleInfo( el ) + borderInfo: new PIE.BorderStyleInfo( el ), + paddingInfo: new PIE.PaddingStyleInfo( el ) }; styleInfosArr = [ styleInfos.backgroundInfo, - styleInfos.borderImageInfo + styleInfos.borderInfo, + styleInfos.borderImageInfo, + styleInfos.paddingInfo ]; rootRenderer = new PIE.IE9RootRenderer( el, boundsInfo, styleInfos ); childRenderers = [ @@ -124,6 +127,7 @@ PIE.Element = (function() { borderImageInfo: new PIE.BorderImageStyleInfo( el ), borderRadiusInfo: new PIE.BorderRadiusStyleInfo( el ), boxShadowInfo: new PIE.BoxShadowStyleInfo( el ), + paddingInfo: new PIE.PaddingStyleInfo( el ), visibilityInfo: new PIE.VisibilityStyleInfo( el ) }; styleInfosArr = [ @@ -132,6 +136,7 @@ PIE.Element = (function() { styleInfos.borderImageInfo, styleInfos.borderRadiusInfo, styleInfos.boxShadowInfo, + styleInfos.paddingInfo, styleInfos.visibilityInfo ]; rootRenderer = new PIE.RootRenderer( el, boundsInfo, styleInfos ); diff --git a/sources/IE9BackgroundRenderer.js b/sources/IE9BackgroundRenderer.js index baab202..59e19ef 100644 --- a/sources/IE9BackgroundRenderer.js +++ b/sources/IE9BackgroundRenderer.js @@ -21,7 +21,8 @@ PIE.IE9BackgroundRenderer = PIE.RendererBase.newRenderer( { draw: function() { var me = this, - bgInfo = me.styleInfos.backgroundInfo, + styleInfos = me.styleInfos, + bgInfo = styleInfos.backgroundInfo, props = bgInfo.getProps(), bg, images, i = 0, img, bgAreaSize, bgSize; @@ -32,10 +33,10 @@ PIE.IE9BackgroundRenderer = PIE.RendererBase.newRenderer( { if ( images ) { while( img = images[ i++ ] ) { if (img.imgType === 'linear-gradient' ) { - bgAreaSize = bgInfo.getBgAreaSize( bg.bgOrigin, me.boundsInfo, me.styleInfos.borderInfo ), + bgAreaSize = bgInfo.getBgAreaSize( bg.bgOrigin, me.boundsInfo, styleInfos.borderInfo, styleInfos.paddingInfo ); bgSize = ( img.bgSize || PIE.BgSize.DEFAULT ).pixels( me.targetElement, bgAreaSize.w, bgAreaSize.h, bgAreaSize.w, bgAreaSize.h - ), + ); bg.push( 'url(data:image/svg+xml,' + escape( me.getGradientSvg( img, bgSize.w, bgSize.h ) ) + ') ' + me.bgPositionToString( img.bgPosition ) + ' / ' + bgSize.w + 'px ' + bgSize.h + 'px ' + diff --git a/sources/ImgRenderer.js b/sources/ImgRenderer.js index df24184..c82942c 100644 --- a/sources/ImgRenderer.js +++ b/sources/ImgRenderer.js @@ -33,8 +33,7 @@ PIE.ImgRenderer = PIE.RendererBase.newRenderer( { el = this.targetElement, src = el.src, round = Math.round, - cs = el.currentStyle, - getLength = PIE.getLength, + paddings = this.styleInfos.paddingInfo.getProps(), zero; // In IE6, the BorderRenderer will have hidden the border by moving the border-width to @@ -47,10 +46,10 @@ PIE.ImgRenderer = PIE.RendererBase.newRenderer( { shape.setAttrs( 'path', this.getBoxPath( - round( borderWidths['t'].pixels( el ) + getLength( cs.paddingTop ).pixels( el ) ), - round( borderWidths['r'].pixels( el ) + getLength( cs.paddingRight ).pixels( el ) ), - round( borderWidths['b'].pixels( el ) + getLength( cs.paddingBottom ).pixels( el ) ), - round( borderWidths['l'].pixels( el ) + getLength( cs.paddingLeft ).pixels( el ) ), + round( borderWidths['t'].pixels( el ) + paddings[ 't' ].pixels( el ) ), + round( borderWidths['r'].pixels( el ) + paddings[ 'r' ].pixels( el ) ), + round( borderWidths['b'].pixels( el ) + paddings[ 'b' ].pixels( el ) ), + round( borderWidths['l'].pixels( el ) + paddings[ 'l' ].pixels( el ) ), 2 ) ); diff --git a/sources/PaddingStyleInfo.js b/sources/PaddingStyleInfo.js new file mode 100644 index 0000000..1c66c86 --- /dev/null +++ b/sources/PaddingStyleInfo.js @@ -0,0 +1,35 @@ +/** + * Handles parsing, caching, and detecting changes to padding CSS + * @constructor + * @param {Element} el the target element + */ +PIE.PaddingStyleInfo = PIE.StyleInfoBase.newStyleInfo( { + + parseCss: function( css ) { + var tokenizer = new PIE.Tokenizer( css ), + arr = [], + token; + + while( ( token = tokenizer.next() ) && token.isLengthOrPercent() ) { + arr.push( PIE.getLength( token.tokenValue ) ); + } + return arr.length > 0 && arr.length < 5 ? { + 't': arr[0], + 'r': arr[1] || arr[0], + 'b': arr[2] || arr[0], + 'l': arr[3] || arr[1] || arr[0] + } : null; + }, + + getCss: PIE.StyleInfoBase.cacheWhenLocked( function() { + var el = this.targetElement, + rs = el.runtimeStyle, + rsPadding = rs.padding, + padding; + if( rsPadding ) rs.padding = ''; + padding = el.currentStyle.padding; + if( rsPadding ) rs.padding = rsPadding; + return padding; + } ) + +} );