view release on metacpan or search on metacpan
lib/CSS/DOM.pm view on Meta::CPAN
=item CSS::DOM::parse
See L</CONSTRUCTORS>, above.
=item CSS::DOM::compute_style( %options )
B<Warning:> This is still highly experimental and crawling with bugs.
This computes the style for a given HTML element. It does not yet calculate
actual measurements (e.g., converting percentages to pixels), but simply
applies the cascading rules and selectors. Pseudo-classes are
not yet supported (but pseudo-elements are).
The precedence rules for normal vs important declarations in the CSS 2
specification are used. (CSS 2.1 is unclear.) The precedence is as follows,
from lowest to highest:
user agent normal declarations
user normal declarations
author normal "
lib/CSS/DOM/Parser.pm view on Meta::CPAN
my $_nl = qr/\r\n?|[\n\f]/;
my $_invalid_qq = qr/"[^\n\r\f\\"]*(?:(?:\\$_nl|$_escape)[^\n\r\f\\"]*)*/;
my $_invalid_q = qr/'[^\n\r\f\\']*(?:(?:\\$_nl|$_escape)[^\n\r\f\\']*)*/;
my $ident = qr/-?$_id_start$_id_cont*/;
my $at = qr/\@$ident/;
my $str = qr/$_invalid_qq(?:"|\z)|$_invalid_q(?:'|\z)/;
my $invalid = qr/$_invalid_qq|$_invalid_q/;
my $hash = qr/#$_id_cont+/;
my $num = qr/(?=\.?[0-9])[0-9]*(?:\.[0-9]*)?/;
my $percent = qr/$num%/;
my $dim = qr/$num$ident/;
my $url = qr/url\($_optspace(?:
$str
|
[^\0- "'()\\\x7f]*(?:$_escape[^\0- "'()\\\x7f]*)*
)$_optspace(?:\)|\z)/x;
my $uni_range = qr/U\+[0-9A-F?]{1,6}(?:-[0-9a-f]{1,6})?/i;
my $space = qr/(?:[ \t\r\n\f]+|\/\*.*?(?:\*\/|\z))[ \t\r\n\f]*
(?:\/\*.*?(?:\*\/|\z)[ \t\r\n\f]*)*/xs;
my $function = qr/$ident\(/;
# Literal tokens are as follows:
# <!-- --> ; { } ( ) [ ] ~= |= , :
# The order of some tokens is important. $url, $uni_range and $function
# have to come before $ident. $url has to come before $function. $percent
# and $dim have to come before $num.
$token_re = qr/\G(?:
($url)|($uni_range)|($function)|($ident)|($at)|($str)|($invalid)|
($hash)|($percent)|($dim)|($num)|(<!--|-->)|(;)|(\{)|(})|(\()|(\))
|(\[)|(])|($space)|(~=)|(\|=)|(,)|(:)|(.)
)/xs;
} # end of tokeniser regexps
# tokenise returns a string of token types in addition to the array of
# tokens so that we can apply grammar rules using regexps. The types are
# as follows:
# u url
# U unicode range
# f function
# i identifier
# @ at keyword
# ' string
# " invalid string (unterminated)
# # hash
# % percentage
# D dimension
# 1 number (not 0, because we want it true)
# < html comment delimiter
# s space/comments
# ~ ~=
# | |=
# d delimiter (miscellaneous character)
# The characters ;{}()[],: represent themselves. The comma and colon are
# actually delimiters according to the CSS 2.1 spec, but itâs more conveni-
# ent to have them as their own tokens.
lib/CSS/DOM/PropertyParser.pm view on Meta::CPAN
"(?:" . cap_start . "(i)(?{ $type_is_ CSS_IDENT })" . cap_end . ")"
: $3 eq 'integer' ?
'(?:' . cap_start . '(1(?(?{index$$tokens[pos()-1],".",==-1})|(?!)))'
. "(?{ $type_is_ CSS_NUMBER })" . cap_end . ")"
: $3 eq 'length' ?
"(?:" . cap_start . "($sign\[D1])" . '(?(?{
$$alt_types[pos()-1]eq"l"||$$prepped[pos()-1]eq 0
})|(?!))' . $type_is_dim_or_number . cap_end . ")"
: $3 eq 'number' ?
"(?:" . cap_start . "(1)(?{ $type_is_ CSS_NUMBER })" . cap_end . ")"
: $3 eq 'percentage' ?
"(?:" . cap_start
. "($sign%)(?{ $type_is_ CSS_PERCENTAGE })"
. cap_end . ")"
: $3 eq 'shape' ?
q*(?x:* . cap_start . q*(f
(?(?{$$prepped[pos()-1] eq "rect("})
(?:
(?:
(?:d(?(?{$$alt_types[pos()-1]eq"+"})|(?!)))?[D1](?(?{
$$alt_types[pos()-1]eq"l"||$$prepped[pos()-1] eq 0
lib/CSS/DOM/PropertyParser.pm view on Meta::CPAN
predefined colour or system colour names, or a #
followed by 3 or 6 hex digits, or the 'rgb(...)'
format (rgba is supported, too)
<counter> counter(...)
<frequency> A unit of Hz or kHz
<identifier> An identifier token
<integer> An integer (really?!)
<length> Number followed by a length unit (em, ex, px, in, cm,
mm, pt, pc)
<number> A number token
<percentage> Number followed by %
<shape> rect(...)
<string> A string token
<str/words> A sequence of identifiers or a single string (e.g., a
font name)
<time> A unit of seconds or milliseconds
<url> A URL token
The format for a shorthand property can contain the name of a sub-property
in single ASCII quotes.
lib/CSS/DOM/PropertyParser.pm view on Meta::CPAN
inherit => 0,
},
'background-image' => {
format => '<url> | none',
default => 'none',
inherit => 0,
},
'background-position' => {
format => '[<percentage>|<length>|left|right]
[<percentage>|<length>|top|center|bottom]? |
[top|bottom] [left|center|right]? |
center [<percentage>|<length>|left|right|top|bottom|
center]?',
default => '0% 0%',
inherit => 0,
},
'background-repeat' => {
format => 'repeat | repeat-x | repeat-y | no-repeat',
default => 'repeat',
inherit => 0,
},
lib/CSS/DOM/PropertyParser.pm view on Meta::CPAN
$temp eq $p->{"border-$side-$_"} or return "";
}
length $temp and $ret .= "$temp ";
}
chop $ret;
$ret
},
},
bottom => {
format => '<length>|<percentage>|auto',
default => 'auto',
inherit => 0,
},
'caption-side' => {
format => 'top|bottom',
default => 'top',
inherit => 1,
},
lib/CSS/DOM/PropertyParser.pm view on Meta::CPAN
<str/words>)
[,(serif|sans-serif|cursive|fantasy|monospace|
<str/words>)]*',
default => 'Times, serif',
inherit => 1,
list => 1,
},
'font-size' => {
format => 'xx-small|x-small|small|medium|large|x-large|xx-large|
larger|smaller|<length>|<percentage>',
default => 'medium',
inherit => 1,
},
'font-style' => {
format => 'normal|italic|oblique',
default => 'normal',
inherit => 1,
},
lib/CSS/DOM/PropertyParser.pm view on Meta::CPAN
$ret .= length $p->{'font-size'}
? $p->{'font-size'}
: 'medium';
$ret .= "/$p->{'line-height'}" if length $p->{'line-height'};
$ret .= " " . ($p->{'font-family'} || "Times, serif");
$ret
},
},
height => {
format => '<length>|<percentage>|auto',
default => 'auto',
inherit => 0,
},
left => {
format => '<length>|<percentage>|auto',
default => 'auto',
inherit => 0,
},
'letter-spacing' => { # aka tracking
format => 'normal|<length>',
default => 'normal',
inherit => 1,
},
'line-height' => { # aka leading
format => 'normal|<number>|<length>|<percentage>',
default => "normal",
inherit => 1,
},
'list-style-image' => {
format => '<url>|none',
default => 'none',
inherit => 1,
},
lib/CSS/DOM/PropertyParser.pm view on Meta::CPAN
for(qw/ type position image /) {
$p->{"list-style-$_"}
and $ret .= $p->{"list-style-$_"}." ";
}
chop $ret;
$ret || 'disc'
},
},
'margin-right' => {
format => '<length>|<percentage>|auto',
default => '0',
inherit => 0,
},
'margin-left' => {
format => '<length>|<percentage>|auto',
default => '0',
inherit => 0,
},
'margin-top' => {
format => '<length>|<percentage>|auto',
default => '0',
inherit => 0,
},
'margin-bottom' => {
format => '<length>|<percentage>|auto',
default => '0',
inherit => 0,
},
margin => {
format => "(<length>|<percentage>|auto)
[ (<length>|<percentage>|auto)
[ (<length>|<percentage>|auto)
(<length>|<percentage>|auto)?
]?
]?",
properties => {
'margin-top' => [1],
'margin-right' => [2,1],
'margin-bottom' => [3,1],
'margin-left' => [4,2,1],
},
serialise => sub {
my $p = shift;
my @vals = map $p->{"margin-$_"},
qw/top right bottom left/;
$vals[3] eq $vals[1] and pop @vals,
$vals[2] eq $vals[0] and pop @vals,
$vals[1] eq $vals[0] and pop @vals;
return join " ", map $_ || 0, @vals;
},
},
'max-height' => {
format => '<length>|<percentage>|none',
default => 'none',
inherit => 0,
},
'max-width' => {
format => '<length>|<percentage>|none',
default => 'none',
inherit => 0,
},
'min-height' => {
format => '<length>|<percentage>|none',
default => 'none',
inherit => 0,
},
'min-width' => {
format => '<length>|<percentage>|none',
default => 'none',
inherit => 0,
},
orphans => {
format => '<integer>',
default => 2,
inherit => 1,
},
lib/CSS/DOM/PropertyParser.pm view on Meta::CPAN
},
},
overflow => {
format => 'visible|hidden|scroll|auto',
default => 'visible',
inherit => 0,
},
'padding-top' => {
format => '<length>|<percentage>',
default => 0,
inherit => 0,
},
'padding-right' => {
format => '<length>|<percentage>',
default => 0,
inherit => 0,
},
'padding-bottom' => {
format => '<length>|<percentage>',
default => 0,
inherit => 0,
},
'padding-left' => {
format => '<length>|<percentage>',
default => 0,
inherit => 0,
},
padding => {
format => "(<length>|<percentage>)
[ (<length>|<percentage>)
[ (<length>|<percentage>)
(<length>|<percentage>)?
]?
]?",
properties => {
'padding-top' => [1],
'padding-right' => [2,1],
'padding-bottom' => [3,1],
'padding-left' => [4,2,1],
},
serialise => sub {
my $p = shift;
lib/CSS/DOM/PropertyParser.pm view on Meta::CPAN
inherit => 0,
},
'page-break-inside' => {
format => 'avoid|auto',
default => 'auto',
inherit => 1,
},
'pause-after' => {
format => '<time>|<percentage>',
default => 0,
inherit => 0,
},
'pause-before' => {
format => '<time>|<percentage>',
default => 0,
inherit => 0,
},
pause => {
format => '(<time>|<percentage>)(<time>|<percentage>)?',
properties => {
'pause-before' => [1],
'pause-after' => [2,1],
}
},
'pitch-range' => {
format => '<number>',
default => 50,
inherit => 1,
lib/CSS/DOM/PropertyParser.pm view on Meta::CPAN
list => 1,
},
richness => {
format => '<number>',
default => 50,
inherit => 1,
},
right => {
format => '<length>|<percentage>|auto',
default => 'auto',
inherit => 0,
},
'speak-header' => {
format => 'once|always',
default => 'once',
inherit => 1,
},
lib/CSS/DOM/PropertyParser.pm view on Meta::CPAN
inherit => 1,
},
'text-decoration' => {
format => 'none | underline||overline||line-through||blink ',
default => 'none',
inherit => 0,
},
'text-indent' => {
format => '<length>|<percentage>',
default => 0,
inherit => 1,
},
'text-transform' => {
format => 'capitalize|uppercase|lowercase|none',
default => 'none',
inherit => 1,
},
top => {
format => '<length>|<percentage>|auto',
default => 'auto',
inherit => 0,
},
'unicode-bidi' => {
format => 'normal|embed|bidi-override',
default => 'normal',
inherit => 0,
},
'vertical-align' => {
format => 'baseline|sub|super|top|text-top|middle|bottom|
text-bottom|<percentage>|<length>',
default => 'baseline',
inherit => 0,
},
visibility => {
format => 'visible|hidden|collapse',
default => 'visible',
inherit => 1,
},
'voice-family' => {
format => '(male|female|child|<str/words>)
[, (male|female|child|<str/words>) ]*',
default => '',
inherit => 1,
list => 1,
},
volume => {
format => '<number>|<percentage>|silent|x-soft|soft|medium|loud|
x-loud',
default => 'medium',
inherit => 1,
},
'white-space' => {
format => 'normal|pre|nowrap|pre-wrap|pre-line',
default => 'normal',
inherit => 1,
},
widows => {
format => '<integer>',
default => 2,
inherit => 1,
},
width => {
format => '<length>|<percentage>|auto',
default => 'auto',
inherit => 0,
},
'word-spacing' => {
format => 'normal|<length>',
default => 'normal',
inherit => 1,
},
lib/CSS/DOM/Value/Primitive.pm view on Meta::CPAN
$val_obj->primitiveType
== CSS_NUMBER
){
not $val % 17 and $val == int $val
and $val > 0 and $val < 256
# ~~~ Would it be faster simply to use
# a regexp?
or undef $ret, last;
$ret .= sprintf "%x", $val/17;
}
else { # percentage
not $val % 20 and $val == int $val
and $val > 0 and $val < 101
# ~~~ Would it be faster simply to use
# a regexp?
or undef $ret, last;
$ret .= sprintf "%x", $val * .15;
}
}
}
if(!$val || $digits == 2) {
lib/CSS/DOM/Value/Primitive.pm view on Meta::CPAN
my $val = $val_obj->getFloatValue;
if(
$val_obj->primitiveType
== CSS_NUMBER
){
$val == int $val
and $val > 0 and $val < 256
or undef $ret, last;
$ret .= sprintf "%02x", $val;
}
elsif($digits == 2) { # percentage
not $val % 20 and $val == int $val
and $val > 0 and $val < 101
# ~~~ Would it be faster simply to use
# a regexp?
or undef $ret, last;
$ret .= sprintf "%02x",$val * 2.55;
}
}
}
$ret and substr $ret,0,0, = '#';
lib/CSS/DOM/Value/Primitive.pm view on Meta::CPAN
[type => CSS_NUMBER, value => $_],
@$rgb
];
}
}
for my $val($$self[valu][$index]) {
if(ref $val eq 'ARRAY') {
$val = new
__PACKAGE__,
owner => $$self[ownr],
format => $index == 3 ? '<number>' : '<number>|<percentage>',
@$val;
delete $$self[csst];
}
elsif(!defined $val and $index == 3) { # alpha
$val = new
__PACKAGE__,
owner => $$self[ownr],
format => '<number>',
type => CSS_NUMBER,
value => 1;
t/CSSPrimitiveValue.t view on Meta::CPAN
$v->cssText('50%');
is $v->cssText, '50%',
'setting cssText on a sub-value of a colour to 50% works';
is $v->primitiveType, &CSS::DOM::Value::Primitive::CSS_PERCENTAGE,
'changing the cssText of a colourâs sub-value changes the prim type';
like $clr->cssText, qr/^rgb\(127.5,\s*255,\s*238\)\z/,
'the colourâs cssText after making the subvalues mixed numbers & %âs';
$v = $clr->alpha;
$v->cssText('50%');
is $v->cssText, 1,
'alpha values ignore assignments of percentage values to cssText';
$v->cssText(.5);
is $v->cssText, .5,
'but number assignments (to alpha valuesâ cssText) work';
like $clr->cssText, qr/^rgba\(127.5,\s*255,\s*238,\s*0.5\)\z/,
'the colourâs cssText after making the subvalues mixed numbers & %âs';
$v = $s->getPropertyCSSValue('color');
$v->cssText('activeborder');;
is $v->primitiveType, &CSS::DOM::Value::Primitive::CSS_IDENT,
'setting a colour propertyâs cssText to a sys. colour makes it an ident';
t/CSSValue.t view on Meta::CPAN
test_value $s,"top","", [type => &CSS_INHERIT], 'inherit', &CSS_INHERIT,
'inherit';
test_value $s,"background-position", "",
[type=>&CSS_CUSTOM,value=>"top left"],
'top left', &CSS_CUSTOM, 'custom value';
use tests 130;
my $css_num = &CSS::DOM::Value::Primitive::CSS_NUMBER;
for( #constant constructor val arg prop css str test name
[ number => '73' , 'z-index', '73' , 'number' ],
[ percentage => '73' , 'top' , '73%' , '%' ],
[ ems => '73' , 'top' , '73em' , 'em' ],
[ exs => '73' , 'top' , '73ex' , 'ex' ],
[ px => '73' , 'top' , '73px' , 'px' ],
[ cm => '73' , 'top' , '73cm' , 'cm' ],
[ mm => '73' , 'top' , '73mm' , 'mm' ],
[ in => '73' , 'top' , '73in' , 'inch' ],
[ pt => '73' , 'top' , '73pt' , 'point' ],
[ pc => '73' , 'top' , '73pc' , 'pica' ],
[ deg => '73' , 'azimuth', '73deg' , 'degree' ],
[ rad => '73' , 'azimuth', '73rad' , 'radian' ],
t/CSSValue.t view on Meta::CPAN
$v->cssText('50%');
is $v->cssText, '50%',
'setting cssText on a sub-value of a colour to 50% works';
is $v->primitiveType, &CSS::DOM::Value::Primitive::CSS_PERCENTAGE,
'changing the cssText of a colourâs sub-value changes the prim type';
like $clr->cssText, qr/^rgb\(127.5,\s*255,\s*238\)\z/,
'the colourâs cssText after making the subvalues mixed numbers & %âs';
$v = $clr->alpha;
$v->cssText('50%');
is $v->cssText, 1,
'alpha values ignore assignments of percentage values to cssText';
$v->cssText(.5);
is $v->cssText, .5,
'but number assignments (to alpha valuesâ cssText) work';
like $clr->cssText, qr/^rgba\(127.5,\s*255,\s*238,\s*0.5\)\z/,
'the colourâs cssText after making the subvalues mixed numbers & %âs';
$v = $s->getPropertyCSSValue('color');
$v->cssText('activeborder');;
is $v->primitiveType, &CSS::DOM::Value::Primitive::CSS_IDENT,
'setting a colour propertyâs cssText to a sys. colour makes it an ident';
t/parser-tokens.t view on Meta::CPAN
is $rule->href, "", q"'";
$rule->cssText('@import ' . q'"');
is $rule->href, '', '"';
}
# ~~~ once both selectors mean something and getCSSPropertyValue is imple-
# mented, we need #hash tests
# ~~~ numbers
# ~~~ percent
# ~~~ dimensions
use tests 23; # urls
{
my $rule = new CSS'DOM'Rule::Import;
$rule->cssText('@import url(!$#%&][\\\}|{*~foo/bar.gif)');
is $rule->href, '!$#%&][\}|{*~foo/bar.gif', 'unquoted url';
$rule->cssText('@import url(/*foo*/foo/bar.gif/*bar)');