Permalink
Browse files

Work in progress on border-image support for IE9.

  • Loading branch information...
1 parent d0323d9 commit ef5ccac8dcbe0ae3109a988dfd8a05a84c3fe42b Jason Johnston committed with Jason Johnston Jun 5, 2011
Showing with 173 additions and 8 deletions.
  1. +1 −0 build.xml
  2. +9 −4 sources/Element.js
  3. +1 −1 sources/IE9BackgroundRenderer.js
  4. +159 −0 sources/IE9BorderImageRenderer.js
  5. +3 −3 tests/border-image-test.html
View
@@ -45,6 +45,7 @@
<!--<fileset file="${src_dir}/BoxShadowInsetRenderer.js" />-->
<fileset file="${src_dir}/ImgRenderer.js" />
<fileset file="${src_dir}/IE9BackgroundRenderer.js" />
+ <fileset file="${src_dir}/IE9BorderImageRenderer.js" />
<fileset file="${src_dir}/Element.js" />
<fileset file="${src_dir}/PIE_API.js" />
<fileset file="${src_dir}/PIE_close.js" />
View
@@ -72,13 +72,16 @@ PIE.Element = (function() {
// Create the style infos and renderers
if ( ieDocMode === 9 ) {
styleInfos = {
- backgroundInfo: new PIE.BackgroundStyleInfo( el )
+ backgroundInfo: new PIE.BackgroundStyleInfo( el ),
+ borderImageInfo: new PIE.BorderImageStyleInfo( el )
};
styleInfosArr = [
- styleInfos.backgroundInfo
+ styleInfos.backgroundInfo,
+ styleInfos.borderImageInfo
];
renderers = [
- new PIE.IE9BackgroundRenderer( el, boundsInfo, styleInfos )
+ new PIE.IE9BackgroundRenderer( el, boundsInfo, styleInfos ),
+ new PIE.IE9BorderImageRenderer( el, boundsInfo, styleInfos )
];
} else {
@@ -129,7 +132,9 @@ PIE.Element = (function() {
if( !eventsAttached ) {
eventsAttached = 1;
- addListener( el, 'onmove', handleMoveOrResize );
+ if( ieDocMode < 9 ) {
+ addListener( el, 'onmove', handleMoveOrResize );
+ }
addListener( el, 'onresize', handleMoveOrResize );
addListener( el, 'onpropertychange', propChanged );
addListener( el, 'onmouseenter', mouseEntered );
@@ -112,7 +112,7 @@ PIE.IE9BackgroundRenderer = PIE.RendererBase.newRenderer( {
},
destroy: function() {
- this.targetElement.runtimeStyle.background = '';
+// this.targetElement.runtimeStyle.background = '';
}
} );
@@ -0,0 +1,159 @@
+/**
+ * Renderer for border-image
+ * @constructor
+ * @param {Element} el The target element
+ * @param {Object} styleInfos The StyleInfo objects
+ * @param {PIE.RootRenderer} parent
+ */
+PIE.IE9BorderImageRenderer = PIE.RendererBase.newRenderer( {
+
+ REPEAT: 'repeat',
+ STRETCH: 'stretch',
+ ROUND: 'round',
+
+ needsUpdate: function() {
+ return this.styleInfos.borderImageInfo.changed();
+ },
+
+ isActive: function() {
+ return this.styleInfos.borderImageInfo.isActive();
+ },
+
+ draw: function() {
+ var me = this,
+ props = me.styleInfos.borderImageInfo.getProps(),
+ bounds = me.boundsInfo.getBounds(),
+ repeat = props.repeat,
+ repeatH = repeat.h,
+ repeatV = repeat.v,
+ el = me.targetElement;
+
+ PIE.Util.withImageSize( props.src, function( imgSize ) {
+ var elW = bounds.w,
+ elH = bounds.h,
+ imgW = imgSize.w,
+ imgH = imgSize.h,
+
+ // The image cannot be referenced as a URL directly in the SVG because IE9 throws a strange
+ // security exception (perhaps due to cross-origin policy within data URIs?) Therefore we
+ // work around this by converting the image data into a data URI itself using a transient
+ // canvas. This unfortunately requires the border-image src to be within the same domain,
+ // which isn't a limitation in true border-image, so we need to try and find a better fix.
+ imgSrc = me.imageToDataURI( props.src, imgW, imgH ),
+
+ REPEAT = me.REPEAT,
+ STRETCH = me.STRETCH,
+ ROUND = me.ROUND,
+ ceil = Math.ceil,
+
+ widths = props.width,
+ widthT = widths.t.pixels( el ),
+ widthR = widths.r.pixels( el ),
+ widthB = widths.b.pixels( el ),
+ widthL = widths.l.pixels( el ),
+ slices = props.slice,
+ sliceT = slices.t.pixels( el ),
+ sliceR = slices.r.pixels( el ),
+ sliceB = slices.b.pixels( el ),
+ sliceL = slices.l.pixels( el ),
+ centerW = elW - widthL - widthR,
+ middleH = elH - widthT - widthB,
+ imgCenterW = imgW - sliceL - sliceR,
+ imgMiddleH = imgH - sliceT - sliceB,
+
+ // Determine the size of each tile - 'round' is handled below
+ tileSizeT = repeatH === STRETCH ? centerW : imgCenterW * widthT / sliceT,
+ tileSizeR = repeatV === STRETCH ? middleH : imgMiddleH * widthR / sliceR,
+ tileSizeB = repeatH === STRETCH ? centerW : imgCenterW * widthB / sliceB,
+ tileSizeL = repeatV === STRETCH ? middleH : imgMiddleH * widthL / sliceL,
+
+ svg,
+ patterns = [],
+ rects = [],
+ i = 0;
+
+ // For 'round', subtract from each tile's size enough so that they fill the space a whole number of times
+ if (repeatH === ROUND) {
+ tileSizeT -= (tileSizeT - (centerW % tileSizeT || tileSizeT)) / ceil(centerW / tileSizeT);
+ tileSizeB -= (tileSizeB - (centerW % tileSizeB || tileSizeB)) / ceil(centerW / tileSizeB);
+ }
+ if (repeatV === ROUND) {
+ tileSizeR -= (tileSizeR - (middleH % tileSizeR || tileSizeR)) / ceil(middleH / tileSizeR);
+ tileSizeL -= (tileSizeL - (middleH % tileSizeL || tileSizeL)) / ceil(middleH / tileSizeL);
+ }
+
+
+ // Build the SVG for the border-image rendering. Add each piece as a pattern, which is then stretched
+ // or repeated as the fill of a rect of appropriate size.
+ svg = [
+ '<svg width="' + elW + '" height="' + elH + '" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">'
+ ];
+
+ function addImage( x, y, w, h, cropX, cropY, cropW, cropH, tileW, tileH ) {
+ patterns.push(
+ '<pattern patternUnits="userSpaceOnUse" id="pattern' + i + '" ' +
+ 'x="' + (repeatH === REPEAT ? x + w / 2 - tileW / 2 : x) + '" ' +
+ 'y="' + (repeatV === REPEAT ? y + h / 2 - tileH / 2 : y) + '" ' +
+ 'width="' + tileW + '" height="' + tileH + '">' +
+ '<svg width="' + tileW + '" height="' + tileH + '" viewBox="' + cropX + ' ' + cropY + ' ' + cropW + ' ' + cropH + '" preserveAspectRatio="none">' +
+ '<image xlink:href="' + imgSrc + '" x="0" y="0" width="' + imgW + '" height="' + imgH + '" />' +
+ '</svg>' +
+ '</pattern>'
+ );
+ rects.push(
+ '<rect x="' + x + '" y="' + y + '" width="' + w + '" height="' + h + '" fill="url(#pattern' + i + ')" />'
+ );
+ i++;
+ }
+ addImage( 0, 0, widthL, widthT, 0, 0, sliceL, sliceT, widthL, widthT ); // top left
+ addImage( widthL, 0, centerW, widthT, sliceL, 0, imgCenterW, sliceT, tileSizeT, widthT ); // top center
+ addImage( elW - widthR, 0, widthR, widthT, imgW - sliceR, 0, sliceR, sliceT, widthR, widthT ); // top right
+ addImage( 0, widthT, widthL, middleH, 0, sliceT, sliceL, imgMiddleH, widthL, tileSizeL ); // middle left
+ if ( props.fill ) {
+ addImage( widthL, widthT, centerW, middleH, sliceL, sliceT, imgCenterW, imgMiddleH, tileSizeT, tileSizeL ); // center fill
+ }
+ addImage( elW - widthR, widthT, widthR, middleH, imgW - sliceR, sliceT, sliceR, imgMiddleH, widthR, tileSizeR ); // middle right
+ addImage( 0, elH - widthB, widthL, widthB, 0, imgH - sliceB, sliceL, sliceB, widthL, widthB ); // bottom left
+ addImage( widthL, elH - widthB, centerW, widthB, sliceL, imgH - sliceB, imgCenterW, sliceB, tileSizeB, widthB ); // bottom center
+ addImage( elW - widthR, elH - widthB, widthR, widthB, imgW - sliceR, imgH - sliceB, sliceR, sliceB, widthR, widthB ); // bottom right
+
+ svg.push(
+ '<defs>' +
+ patterns.join('\n') +
+ '</defs>' +
+ rects.join('\n') +
+ '</svg>'
+ );
+
+ el.runtimeStyle.background = 'url(data:image/svg+xml,' + escape( svg.join( '' ) ) + ') no-repeat border-box border-box';
+ el.runtimeStyle.borderColor = 'transparent';
+ }, me );
+ },
+
+ /**
+ * Convert a given image to a data URI
+ */
+ imageToDataURI: (function() {
+ var uris = {};
+ return function( src, width, height ) {
+ var uri = uris[ src ],
+ image, canvas;
+ if ( !uri ) {
+ image = new Image();
+ canvas = doc.createElement( 'canvas' );
+ image.src = src;
+ canvas.width = width;
+ canvas.height = height;
+ canvas.getContext( '2d' ).drawImage( image, 0, 0 );
+ uri = uris[ src ] = canvas.toDataURL();
+ }
+ return uri;
+ }
+ })(),
+
+ destroy: function() {
+ var rs = this.targetElement.runtimeStyle;
+ rs.background = rs.borderColor = '';
+ }
+
+} );
@@ -22,20 +22,20 @@
}
#test1 {
- border-image: url(border.png) 27 fill stretch;
+ border-image: url(border.png) 27 stretch;
border-image: url(border.png) 27 fill stretch;
-moz-border-image: url(border.png) 27 stretch;
-webkit-border-image: url(border.png) 27 stretch;
}
#test2 {
border-image: url(border.png) 27 repeat;
- border-image: url(border.png) 27 repeat;
+ border-image: url(border.png) 27 fill repeat;
-moz-border-image: url(border.png) 27 repeat;
-webkit-border-image: url(border.png) 27 repeat;
}
#test3 {
border-image: url(border.png) 27 round;
- border-image: url(border.png) 27 round;
+ border-image: url(border.png) 27 fill round;
-moz-border-image: url(border.png) 27 round;
-webkit-border-image: url(border.png) 27 round;
}

0 comments on commit ef5ccac

Please sign in to comment.