Permalink
Browse files

Solid start to text-shadow implementation for IE6-8. Parsing is compl…

…eted; elements with single text nodes are rendered properly with offsets, blur, and color/alpha that match Gecko and WebKit rendering very closely. Needs to be enhanced to handle deep mixed markup, react to content changes, and to work in IE9.
  • Loading branch information...
1 parent 95737dd commit bc3a28fe915987d8d8c2451347f7cab031e1edbd Jason Johnston committed Jun 10, 2011
View
@@ -33,6 +33,7 @@
<fileset file="${src_dir}/BorderRadiusStyleInfo.js" />
<fileset file="${src_dir}/BorderImageStyleInfo.js" />
<fileset file="${src_dir}/BoxShadowStyleInfo.js" />
+ <fileset file="${src_dir}/TextShadowStyleInfo.js" />
<fileset file="${src_dir}/VisibilityStyleInfo.js" />
<fileset file="${src_dir}/RendererBase.js" />
<fileset file="${src_dir}/RootRenderer.js" />
@@ -42,6 +43,7 @@
<fileset file="${src_dir}/BoxShadowOutsetRenderer.js" />
<!--<fileset file="${src_dir}/BoxShadowInsetRenderer.js" />-->
<fileset file="${src_dir}/ImgRenderer.js" />
+ <fileset file="${src_dir}/TextShadowRenderer.js" />
<fileset file="${src_dir}/IE9BackgroundRenderer.js" />
<fileset file="${src_dir}/Element.js" />
<fileset file="${src_dir}/PIE_API.js" />
@@ -20,6 +20,7 @@ PIE.BackgroundRenderer = PIE.RendererBase.newRenderer( {
return si.borderImageInfo.isActive() ||
si.borderRadiusInfo.isActive() ||
si.backgroundInfo.isActive() ||
+ si.textShadowInfo.isActive() ||
( si.boxShadowInfo.isActive() && si.boxShadowInfo.getProps().inset );
},
@@ -12,6 +12,7 @@ PIE.BoxShadowStyleInfo = PIE.StyleInfoBase.newStyleInfo( {
var props,
getLength = PIE.getLength,
Type = PIE.Tokenizer.Type,
+ isTextShadow = this.isTextShadow,
tokenizer;
if( css ) {
@@ -38,6 +39,10 @@ PIE.BoxShadowStyleInfo = PIE.StyleInfoBase.newStyleInfo( {
color = value;
}
else if( type & Type.IDENT && value === 'inset' && !inset ) {
+ if (isTextShadow) {
+ // text-shadow does not allow 'inset' keyword
+ return false;
+ }
inset = true;
}
else { //encountered an unrecognized token; fail.
@@ -46,7 +51,7 @@ PIE.BoxShadowStyleInfo = PIE.StyleInfoBase.newStyleInfo( {
}
len = lengths && lengths.length;
- if( len > 1 && len < 5 ) {
+ if( len > 1 && len < ( isTextShadow ? 4 : 5 ) ) {
( inset ? props.inset : props.outset ).push( {
xOffset: getLength( lengths[0].tokenValue ),
yOffset: getLength( lengths[1].tokenValue ),
View
@@ -88,6 +88,7 @@ PIE.Element = (function() {
borderImageInfo: new PIE.BorderImageStyleInfo( el ),
borderRadiusInfo: new PIE.BorderRadiusStyleInfo( el ),
boxShadowInfo: new PIE.BoxShadowStyleInfo( el ),
+ textShadowInfo: new PIE.TextShadowStyleInfo( el ),
visibilityInfo: new PIE.VisibilityStyleInfo( el )
};
styleInfosArr = [
@@ -96,6 +97,7 @@ PIE.Element = (function() {
styleInfos.borderImageInfo,
styleInfos.borderRadiusInfo,
styleInfos.boxShadowInfo,
+ styleInfos.textShadowInfo,
styleInfos.visibilityInfo
];
@@ -105,7 +107,8 @@ PIE.Element = (function() {
new PIE.BackgroundRenderer( el, boundsInfo, styleInfos, rootRenderer ),
//new PIE.BoxShadowInsetRenderer( el, boundsInfo, styleInfos, rootRenderer ),
new PIE.BorderRenderer( el, boundsInfo, styleInfos, rootRenderer ),
- new PIE.BorderImageRenderer( el, boundsInfo, styleInfos, rootRenderer )
+ new PIE.BorderImageRenderer( el, boundsInfo, styleInfos, rootRenderer ),
+ new PIE.TextShadowRenderer( el, boundsInfo, styleInfos, rootRenderer )
];
if( el.tagName === 'IMG' ) {
childRenderers.push( new PIE.ImgRenderer( el, boundsInfo, styleInfos, rootRenderer ) );
@@ -0,0 +1,67 @@
+/**
+ * Renderer for text-shadows
+ * @constructor
+ * @param {Element} el The target element
+ * @param {Object} styleInfos The StyleInfo objects
+ * @param {PIE.RootRenderer} parent
+ */
+PIE.TextShadowRenderer = PIE.RendererBase.newRenderer( {
+
+ boxZIndex: 7,
+ boxName: 'text-shadow',
+ textStyles: [ 'fontSize', 'fontFamily', 'fontStyle', 'fontWeight', 'letterSpacing', 'lineHeight', 'textDecoration' ],
+
+ needsUpdate: function() {
+ return this.styleInfos.textShadowInfo.changed();
+ },
+
+ isActive: function() {
+ var textShadowInfo = this.styleInfos.textShadowInfo;
+ return textShadowInfo.isActive() && textShadowInfo.getProps();
+ },
+
+
+ draw: function() {
+ var el = this.targetElement,
+ currentStyle = el.currentStyle,
+ box = this.getBox(),
+ shadowProps = this.styleInfos.textShadowInfo.getProps(),
+ i = shadowProps.length,
+ textStyles = this.textStyles,
+ getLength = PIE.getLength,
+ filterPrefix = 'progid:DXImageTransform.Microsoft.',
+ props, shadowEl, shadowStyle, color, blur, glow, j;
+
+ box.style.width = this.boundsInfo.getBounds().w;
+ box.innerHTML = '';
+
+ while( i-- ) {
+ props = shadowProps[ i ];
+ shadowEl = doc.createElement( 'span' );
+ color = props.color;
+ blur = props.blur.pixels( el );
+ glow = blur > 3 ? ( Math.ceil( blur / 4 ) ) : 0;
+
+ shadowStyle = shadowEl.style;
+ shadowStyle.position = 'absolute';
+ shadowStyle.left = props.xOffset.pixels( el ) - blur + getLength( currentStyle.paddingLeft ).pixels( el );
+ shadowStyle.top = props.yOffset.pixels( el ) - blur + getLength( currentStyle.paddingTop ).pixels( el );
+
+ j = textStyles.length;
+ while( j-- ) {
+ shadowStyle[ textStyles[ j ] ] = currentStyle[ textStyles[ j ] ];
+ }
+ shadowStyle.color = color.colorValue( el );
+
+ if ( blur ) {
+ shadowStyle.filter = 'alpha(opacity=' + Math.max( 75 - ( blur * 2 ), 10 ) * color.alpha() + ') ' +
+ (glow ? filterPrefix + 'Glow(Strength=' + ( glow ) + ', Color=' + color.hexValue( el ) + ') ' : '') +
+ filterPrefix + 'Blur(PixelRadius=' + ( blur - glow ) + ', MakeShadow=false)';
+ }
+
+ shadowEl.innerText = el.innerText;
+ box.appendChild( shadowEl );
+ }
+ }
+
+} );
@@ -0,0 +1,19 @@
+/**
+ * Handles parsing, caching, and detecting changes to text-shadow CSS. The text-shadow
+ * format matches box-shadow exactly except that it does not allow the 'inset' keyword,
+ * so it uses the parsing logic from BoxShadowStyleInfo but removes any inset info.
+ * @constructor
+ * @param {Element} el the target element
+ */
+PIE.TextShadowStyleInfo = PIE.StyleInfoBase.newStyleInfo( {
+ cssProperty: 'text-shadow',
+ styleProperty: 'textShadow',
+ isTextShadow: true,
+
+ parseCss: (function( superMethod ) {
+ return function( css ) {
+ var info = superMethod.call( this, css );
+ return (info && info.outset) || null;
+ }
+ })( PIE.BoxShadowStyleInfo.prototype.parseCss )
+} );
@@ -0,0 +1,80 @@
+<!DOCTYPE html>
+<html>
+<head>
+
+ <meta content="text/html; charset=UTF-8" http-equiv="content-type">
+ <title>Basic CSS3 Demos</title>
+
+ <style type="text/css">
+ body {
+ font-size: 18px;
+ font-family: Arial;
+ }
+
+ /* From http://www.w3.org/Style/Examples/007/text-shadow */
+ #w3c-tests div {
+ float: left;
+ padding: .5em;
+ margin: .25em;
+ font-size: 20px;
+ /*border-radius: 3px;*/
+ behavior: url(../build/PIE_uncompressed.htc);
+ }
+ #w3c1 {background: #CCF; color: blue; text-shadow: #333 0.1em 0.1em}
+ #w3c2 {background: #CCF; color: blue; text-shadow: #333 0.1em 0.1em 0.05em}
+ #w3c3 {background: #CCF; color: blue; text-shadow: black 0.1em 0.1em 0.2em}
+ #w3c4 {background: #EEE; color: white; text-shadow: black 0.1em 0.1em 0.2em}
+ #w3c5 {color: blue; text-shadow: 0.2em 0.5em 0.1em #600, -0.3em 0.1em 0.1em #006600, 0.4em -0.3em 0.1em #006}
+ #w3c6 {background: #CCC; color: #D1D1D1; text-shadow: -1px -1px white, 1px 1px #333; letter-spacing: 2px}
+ #w3c7 {background: #CCC; color: #C8C8C8; text-shadow: 1px 1px white, -1px -1px #444; letter-spacing: 2px}
+ #w3c8 {background: #CCF; color: blue; text-shadow: -1px 0 black, 0 1px black, 1px 0 black, 0 -1px black}
+ #w3c9 {background: #CCF; color: #BBE; text-shadow: -1px 0 black, 0 1px black, 1px 0 black, 0 -1px black}
+ #w3c10 {text-shadow: 0 0 0.2em #8F7}
+ #w3c11 {text-shadow: 0 0 0.2em #F87, 0 0 0.2em #F87}
+ /*#w3c12 {color: #fff; text-shadow: -2px -2px 2px #0000FF, 2px 2px 2px #FF0000, 0 -2px 2px #0000FF, 0 2px 2px #FF0000}*/
+ #w3c12 {text-shadow: 0 0 0.2em #87F, 0 0 0.2em #87F, 0 0 0.2em #87F}
+
+
+ .tester {
+ behavior: url(../build/PIE_uncompressed.htc);
+ padding: 5px;
+ clear: both;
+ }
+ </style>
+</head>
+
+<body>
+
+<div id="w3c-tests">
+ <div id="w3c1">PIE</div>
+ <div id="w3c2">PIE</div>
+ <div id="w3c3">PIE</div>
+ <div id="w3c4">PIE</div>
+ <div id="w3c5">PIE</div>
+ <div id="w3c6">PIE</div>
+ <div id="w3c7">PIE</div>
+ <div id="w3c8">PIE</div>
+ <div id="w3c9">PIE</div>
+ <div id="w3c10">PIE</div>
+ <div id="w3c11">PIE</div>
+ <div id="w3c12">PIE</div>
+</div>
+
+
+<script type="text/javascript">
+ for(var i=1; i<10; i++) {
+ document.write('<div class="tester" style="text-shadow: 4px 4px ' + i + 'px #000">Text shadow blur radius ' + i + '</div>')
+ }
+ for(var i=1; i<10; i++) {
+ document.write('<div class="tester" style="text-shadow: 0 0 ' + i + 'px #F00">Text shadow blur radius ' + i + '</div>')
+ }
+ for(var i=1; i<10; i++) {
+ document.write('<div class="tester" style="text-shadow: 0 0 ' + i + 'px #00F">Text shadow blur radius ' + i + '</div>')
+ }
+ for(var i=1; i<10; i++) {
+ document.write('<div class="tester" style="text-shadow: 0 0 ' + i + 'px #0F0">Text shadow blur radius ' + i + '</div>')
+ }
+</script>
+
+</body>
+</html>

0 comments on commit bc3a28f

Please sign in to comment.