Skip to content

Commit

Permalink
Implement rendering of background-clip. Fix order of gradient opacity.
Browse files Browse the repository at this point in the history
  • Loading branch information
Jason Johnston committed Dec 27, 2011
1 parent 037ffb3 commit 775ce0a
Show file tree
Hide file tree
Showing 7 changed files with 123 additions and 30 deletions.
2 changes: 2 additions & 0 deletions build.xml
Expand Up @@ -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" />
Expand Down Expand Up @@ -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" />
Expand Down
73 changes: 60 additions & 13 deletions sources/BackgroundRenderer.js
Expand Up @@ -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();
Expand All @@ -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();
Expand All @@ -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 );

Expand Down Expand Up @@ -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
),
Expand Down Expand Up @@ -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.
Expand All @@ -178,23 +221,25 @@ 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 );
}
}

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 };
Expand Down Expand Up @@ -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()
);
}
},
Expand Down
16 changes: 10 additions & 6 deletions sources/BackgroundStyleInfo.js
Expand Up @@ -33,6 +33,7 @@ PIE.BackgroundStyleInfo = PIE.StyleInfoBase.newStyleInfo( {
* Format of return object:
* {
* color: <PIE.Color>,
* colorClip: <'border-box' | 'padding-box'>,
* bgImages: [
* {
* imgType: 'image',
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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();
Expand All @@ -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 };
Expand Down
9 changes: 7 additions & 2 deletions sources/Element.js
Expand Up @@ -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 = [
Expand All @@ -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 = [
Expand All @@ -132,6 +136,7 @@ PIE.Element = (function() {
styleInfos.borderImageInfo,
styleInfos.borderRadiusInfo,
styleInfos.boxShadowInfo,
styleInfos.paddingInfo,
styleInfos.visibilityInfo
];
rootRenderer = new PIE.RootRenderer( el, boundsInfo, styleInfos );
Expand Down
7 changes: 4 additions & 3 deletions sources/IE9BackgroundRenderer.js
Expand Up @@ -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;

Expand All @@ -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 ' +
Expand Down
11 changes: 5 additions & 6 deletions sources/ImgRenderer.js
Expand Up @@ -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
Expand All @@ -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
)
);
Expand Down
35 changes: 35 additions & 0 deletions 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.