Skip to content
This repository has been archived by the owner on Apr 20, 2023. It is now read-only.

Commit

Permalink
Convert border-image style parser to use the tokenizer, and make it s…
Browse files Browse the repository at this point in the history
…upport the full spec syntax (though the renderer doesn't yet make use of all the syntax items)
  • Loading branch information
Jason Johnston committed Apr 24, 2010
1 parent 03114eb commit 74fa6fd
Show file tree
Hide file tree
Showing 4 changed files with 148 additions and 55 deletions.
28 changes: 17 additions & 11 deletions sources/BorderImageRenderer.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,12 +47,16 @@ PIE.BorderImageRenderer = (function() {
tl = p['tl'].style,
c = p['c'].style,

slices = props.slice,
widths = props.width,
widthT = widths.t.pixels( el ),
widthR = widths.r.pixels( el ),
widthB = widths.b.pixels( el ),
widthL = widths.l.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 );

tl.height = t.height = tr.height = widthT;
tl.width = l.width = bl.width = widthL;
Expand All @@ -67,28 +71,30 @@ PIE.BorderImageRenderer = (function() {


// image croppings

function setCrops( sides, crop, val ) {
for( var i=0, len=sides.length; i < len; i++ ) {
p[ sides[i] ]['imagedata'][ crop ] = val;
}
}

// corners
setCrops( [ 'tl', 't', 'tr' ], 'cropBottom', ( imgSize.h - slices.t ) / imgSize.h );
setCrops( [ 'tl', 'l', 'bl' ], 'cropRight', ( imgSize.w - slices.l ) / imgSize.w );
setCrops( [ 'bl', 'b', 'br' ], 'cropTop', ( imgSize.h - slices.b ) / imgSize.h );
setCrops( [ 'tr', 'r', 'br' ], 'cropLeft', ( imgSize.w - slices.r ) / imgSize.w );
setCrops( [ 'tl', 't', 'tr' ], 'cropBottom', ( imgSize.h - sliceT ) / imgSize.h );
setCrops( [ 'tl', 'l', 'bl' ], 'cropRight', ( imgSize.w - sliceL ) / imgSize.w );
setCrops( [ 'bl', 'b', 'br' ], 'cropTop', ( imgSize.h - sliceB ) / imgSize.h );
setCrops( [ 'tr', 'r', 'br' ], 'cropLeft', ( imgSize.w - sliceR ) / imgSize.w );

// edges and center
if( props.repeat.v === 'stretch' ) {
setCrops( [ 'l', 'r', 'c' ], 'cropTop', slices.t / imgSize.h );
setCrops( [ 'l', 'r', 'c' ], 'cropBottom', slices.b / imgSize.h );
setCrops( [ 'l', 'r', 'c' ], 'cropTop', sliceT / imgSize.h );
setCrops( [ 'l', 'r', 'c' ], 'cropBottom', sliceB / imgSize.h );
}
if( props.repeat.h === 'stretch' ) {
setCrops( [ 't', 'b', 'c' ], 'cropLeft', slices.l / imgSize.w );
setCrops( [ 't', 'b', 'c' ], 'cropRight', slices.r / imgSize.w );
setCrops( [ 't', 'b', 'c' ], 'cropLeft', sliceL / imgSize.w );
setCrops( [ 't', 'b', 'c' ], 'cropRight', sliceR / imgSize.w );
}

// center fill
c.display = props.fill ? '' : 'none';
}, this );
} else {
this.destroy();
Expand Down
167 changes: 128 additions & 39 deletions sources/BorderImageStyleInfo.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,48 +12,137 @@ PIE.BorderImageStyleInfo = (function() {
cssProperty: PIE.CSS_PREFIX + 'border-image',
styleProperty: PIE.STYLE_PREFIX + 'BorderImage',

//TODO this needs to be reworked to allow the components to appear in arbitrary order
parseRE: new RegExp(
'^\\s*url\\(\\s*([^\\s\\)]+)\\s*\\)\\s+N(\\s+N)?(\\s+N)?(\\s+N)?(\\s*\\/\\s*L(\\s+L)?(\\s+L)?(\\s+L)?)?RR\\s*$'
.replace( /N/g, '(\\d+|' + PIE.StyleBase.percentRE.source + ')' )
.replace( /L/g, PIE.StyleBase.lengthRE.source )
.replace( /R/g, '(\\s+(stretch|round|repeat))?' )
),
repeatIdents: { 'stretch':1, 'round':1, 'repeat':1, 'space':1 },

parseCss: function( css ) {
var cs = this.element.currentStyle,
p = null,
Length = PIE.Length,
m = css && css.match( this.parseRE );

if( m ) {
p = {
src: m[1],

slice: {
t: parseInt( m[2], 10 ),
r: parseInt( m[4] || m[2], 10 ),
b: parseInt( m[6] || m[2], 10 ),
l: parseInt( m[8] || m[4] || m[2], 10 )
},

width: m[9] ? {
t: new Length( m[10] ),
r: new Length( m[12] || m[10] ),
b: new Length( m[14] || m[10] ),
l: new Length( m[16] || m[12] || m[10] )
} : {
t: new Length( cs.borderTopWidth ),
r: new Length( cs.borderRightWidth ),
b: new Length( cs.borderBottomWidth ),
l: new Length( cs.borderLeftWidth )
},

repeat: {
h: m[18] || 'stretch',
v: m[20] || m[18] || 'stretch'
var p = null, tokenizer, token, type, value,
slices, widths, outsets,
slashCount = 0, cs,
Type = PIE.Tokenizer.Type,
IDENT = Type.IDENT,
NUMBER = Type.NUMBER,
LENGTH = Type.LENGTH,
PERCENT = Type.PERCENT;

if( css ) {
tokenizer = new PIE.Tokenizer( css );
p = {};

function isSlash( token ) {
return token && ( token.type & Type.OPERATOR ) && ( token.value === '/' );
}

function isFillIdent( token ) {
return token && ( token.type & IDENT ) && ( token.value === 'fill' );
}

function collectSlicesEtc() {
slices = tokenizer.until( function( tok ) {
return !( tok.type & ( NUMBER | PERCENT ) );
} );

if( isFillIdent( tokenizer.next() ) && !p.fill ) {
p.fill = true;
} else {
tokenizer.prev();
}

if( isSlash( tokenizer.next() ) ) {
slashCount++;
widths = tokenizer.until( function( tok ) {
return !( token.type & ( NUMBER | PERCENT | LENGTH ) ) && !( ( token.type & IDENT ) && token.value === 'auto' );
} );

if( isSlash( tokenizer.next() ) ) {
slashCount++;
outsets = tokenizer.until( function( tok ) {
return !( token.type & ( NUMBER | LENGTH ) );
} );
}
} else {
tokenizer.prev();
}
}

while( token = tokenizer.next() ) {
type = token.type;
value = token.value;

// Numbers and/or 'fill' keyword: slice values. May be followed optionally by width values, followed optionally by outset values
if( type & ( NUMBER | PERCENT ) && !slices ) {
tokenizer.prev();
collectSlicesEtc();
}
else if( isFillIdent( token ) && !p.fill ) {
p.fill = true;
collectSlicesEtc();
}
};

// Idents: one or values for 'repeat'
else if( ( type & IDENT ) && this.repeatIdents[value] && !p.repeat ) {
p.repeat = { h: value };
if( token = tokenizer.next() ) {
if( ( token.type & IDENT ) && this.repeatIdents[token.value] ) {
p.repeat.v = token.value;
} else {
tokenizer.prev();
}
}
}

// URL of the image
else if( ( type & Type.URL ) && !p.src ) {
p.src = value;
}

// Found something unrecognized; exit.
else {
return null;
}
}

// Validate what we collected
if( !p.src || !slices || slices.length < 1 || slices.length > 4 ||
( widths && widths.length > 4 ) || ( slashCount === 1 && widths.length < 1 ) ||
( outsets && outsets.length > 4 ) || ( slashCount === 2 && outsets.length < 1 ) ) {
return null;
}

// Fill in missing values
if( !p.repeat ) {
p.repeat = { h: 'stretch' };
}
if( !p.repeat.v ) {
p.repeat.v = p.repeat.h;
}

function distributeSides( tokens, convertFn ) {
return {
t: convertFn( tokens[0] ),
r: convertFn( tokens[1] || tokens[0] ),
b: convertFn( tokens[2] || tokens[0] ),
l: convertFn( tokens[3] || tokens[1] || tokens[0] )
};
}

p.slice = distributeSides( slices, function( tok ) {
return new PIE.Length( ( tok.type & NUMBER ) ? tok.value + 'px' : tok.value );
} );

p.width = widths && widths.length > 0 ?
distributeSides( widths, function( tok ) {
return tok.type & ( LENGTH | PERCENT ) ? new PIE.Length( tok.value ) : tok.value;
} ) :
( cs = this.element.currentStyle ) && {
t: new PIE.Length( cs.borderTopWidth ),
r: new PIE.Length( cs.borderRightWidth ),
b: new PIE.Length( cs.borderBottomWidth ),
l: new PIE.Length( cs.borderLeftWidth )
};

p.outset = distributeSides( outsets || [ 0 ], function( tok ) {
return tok.type & LENGTH ? new PIE.Length( tok.value ) : tok.value;
} );
}

return p;
Expand Down
2 changes: 0 additions & 2 deletions sources/StyleBase.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
PIE.StyleBase = {
lengthRE: /[\-\+]?\d*\.?\d*(px|em|ex|mm|cm|in|pt|pc)|[\-\+]?0/,
percentRE: /[\-\+]?\d+\.?\d*%|[\-\+]?0/,
urlRE: /^url\(\s*['"]?([^\s\)"]*)['"]?\s*\)$/,
trimRE: /^\s*|\s*$/g,

Expand Down
6 changes: 3 additions & 3 deletions tests/border-image-test.html
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,12 @@
border-width: 20px;
border-bottom-width: 30px;
height:25%;
behavior:url(../build/PIE.htc);
behavior:url(../build/PIE_uncompressed.htc);
}

#test1 {
border-image: url(border.png) 27 stretch;
-pie-border-image: url(border.png) 27 stretch;
border-image: url(border.png) 27 fill stretch;
-pie-border-image: url(border.png) 27 fill stretch;
-moz-border-image: url(border.png) 27 stretch;
-webkit-border-image: url(border.png) 27 stretch;
}
Expand Down

0 comments on commit 74fa6fd

Please sign in to comment.