Browse files

Implement rendering of background-clip. Fix order of gradient opacity.

  • Loading branch information...
1 parent 037ffb3 commit 775ce0a65e9a69d9fe3cc43e43982403bbd19d4c Jason Johnston committed Dec 26, 2011
View
2 build.xml
@@ -40,6 +40,7 @@
<fileset file="${src_dir}/BorderRadiusStyleInfo.js" />
<fileset file="${src_dir}/BorderImageStyleInfo.js" />
<fileset file="${src_dir}/BoxShadowStyleInfo.js" />
+ <fileset file="${src_dir}/PaddingStyleInfo.js" />
<fileset file="${src_dir}/VisibilityStyleInfo.js" />
<fileset file="${src_dir}/VmlShape.js" />
<fileset file="${src_dir}/RendererBase.js" />
@@ -84,6 +85,7 @@
<fileset file="${src_dir}/BackgroundStyleInfo.js" />
<fileset file="${src_dir}/BorderStyleInfo.js" />
<fileset file="${src_dir}/BorderImageStyleInfo.js" />
+ <fileset file="${src_dir}/PaddingStyleInfo.js" />
<fileset file="${src_dir}/RendererBase.js" />
<fileset file="${src_dir}/IE9RootRenderer.js" />
<fileset file="${src_dir}/IE9BackgroundRenderer.js" />
View
73 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
),
@@ -171,30 +172,74 @@ 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.
* @param {String} bgOrigin
*/
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 );
}
}
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()
);
}
},
View
16 sources/BackgroundStyleInfo.js
@@ -33,6 +33,7 @@ PIE.BackgroundStyleInfo = PIE.StyleInfoBase.newStyleInfo( {
* Format of return object:
* {
* color: <PIE.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 };
View
9 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 );
View
7 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 ' +
View
11 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
)
);
View
35 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;
+ } )
+
+} );

0 comments on commit 775ce0a

Please sign in to comment.