Provided by: libcss-dom-perl_0.15-1_all bug

NAME

       CSS::DOM::PropertyParser - Parser for CSS property values

VERSION

       Version 0.15

SYNOPSIS

         use CSS::DOM::PropertyParser;

         $spec = new CSS::DOM::PropertyParser; # empty
         # OR
         $spec = $CSS::DOM::PropertyParser::Default->clone;

         $spec->add_property(
          overflow => {
           format => 'visible|hidden|scroll|auto',
           default => 'visible',
           inherit => 0,
          }
         );

         $hashref = $spec->get_property('overflow');

         $hashref = $spec->delete_property('overflow');

         @names = $spec->property_names;

DESCRIPTION

       Objects of this class provide lists of supported properties for CSS::DOM style sheets.
       They also describe the syntax and parsing of those properties' values.

       Some CSS properties simply have their own values (e.g., overflow); some are abbreviated
       forms of several other properties (e.g., font). These are referred to in this
       documentation as 'simple' and 'shorthand' properties.

CONSTRUCTOR

       "$spec = new CSS::DOM::PropertyParser" returns an object that does not recognise any
       properties, to which you can add your own properties.

       There are two parser objects that come with this module. These are
       $CSS::DOM::PropertyParser::CSS21, which contains all of CSS 2.1, and
       $CSS::DOM::PropertyParser::Default, which is currently identical to the former, but to
       which parts of CSS 3 which eventually be added.

       If one of the default specs will do, you don't need a constructor. Simply pass it to the
       CSS::DOM constructor. If you want to modify it, clone it first, using the "clone" method
       (as shown in the "SYNOPSIS"). It is often convenient to clone the $Default spec and delete
       those properties that are not supported.

METHODS

       clone
           Returns a deep clone of the object. (It's deep so that you can modify the
           hashes/arrays inside it without modifying the original.)

       add_property ( $name, \%spec )
           Adds the specification for the named property. See "HOW INDIVIDUAL PROPERTIES ARE
           SPECIFIED", below.

       get_property ( $name )
           Returns the hashref passed to the previous method.

       delete_property ( $name )
           Deletes the property and returns the hash ref.

       property_names
           Returns a list of the names of supported properties.

       subproperty_names ( $name )
           Returns a list of the names of $name's sub-properties if it is a shorthand property.

       match
           Currently for internal use only. See the source code for documentation.  Use at your
           own risk.

HOW INDIVIDUAL PROPERTIES ARE SPECIFIED

       Before you read this the first time, look at the "Example" below, and then come back and
       use this for reference.

       The specification for an individual property is a hash ref. There are several keys that
       each hash ref can have:

       format
           This is set to a string that describes the format of the property. The syntax used is
           based on the CSS 2.1 spec, but is not exactly the same.  Unlike regular expressions,
           these formats are applied to properties on a token-by-token basis, not one character
           at a time. (This means that "100|200" cannot be written as "[1|2]00", as that would
           mean "1 00 | 2 00".)

           Whitespace is ignored in the format and in the CSS property except as a token
           separator.

           There are several metachars (in order of precedence):

            [...]      grouping (like (?:...) )
            (...)      capturing group (just like a regexp)
            ?          optional
            *          zero or more
            +          one or more
            ||         alternates that can come in any order and are optional,
                       but at least one must be specified  (the order will be
                       retained if possible)
            |          alternates, exactly one of which is required

           In addition, the following datatypes can be specified in angle brackets:

            <angle>       A number with a 'deg', 'rad' or 'grad' suffix
            <attr>        attr(...)
            <colour>      (You can omit the 'u' if you want to.) One of CSS's
                          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.

           All other characters are understood verbatim.

           It is not necessary to include the word 'inherit' in the format, since every property
           supports that.

           "<counter>" makes use of the specification for the list-style-type property. So if you
           modify the latter, it will affect "<counter>" as well.

       default
           The default value. This only applies to simple properties.

       inherit
           Whether the property is inherited.

       special_values
           A hash ref of values that are replaced with other values (e.g.,
           "caption => '13px sans-serif'".) The keys are lowercase identifier names.

           This feature only applies to single identifiers. In fact, it exists solely for the
           font property's use.

       list
           Set to true if the property is a list of values. The capturing parentheses in the
           format determine the individual values of the list.

           This applies to simple properties only.

       properties
           For a shorthand property, list the sub-properties here. The keys are the property
           names. The values are array refs. The elements within the arrays are numbers
           indicating which captures in the format are to be used for the sub-property's value.
           They are tried one after the other. Whichever is the first that matches (null matches
           not counting) is used.

           Sub-properties that are referenced in the "format" need not be listed here.

       serialise
           For shorthand properties only. Set this to a subroutine that serialises the property.
           It is called with a hashref of sub-properties as its sole argument. The values of the
           hash are blank for properties that are set to their initial values. This sub is only
           called when all sub-properties are set.

   Example
         our $CSS21 = new CSS::DOM::PropertyParser;
         my %properties = (
           azimuth => {
            format => '<angle> |
                        [ left-side | far-left | left | center-left |
                          center | center-right | right | far-right |
                          right-inside ] || behind
                       | leftwards | rightwards',
            default => '0',
            inherit => 1,
           },

          'background-attachment' => {
            format  => 'scroll | fixed',
            default => 'scroll',
            inherit => 0,
           },

          'background-color' => {
            format  => '<colour>',
            default => 'transparent',
            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,
           },

           background => {
            format => "'background-color' || 'background-image' ||
                       'background-repeat' || 'background-attachment' ||
                       'background-position'",
            serialise => sub {
             my $p = shift;
             my $ret = '';
             for(qw/ background-color background-image background-repeat
                     background-attachment background-position /) {
              length $p->{$_} and $ret .= "$p->{$_} ";
             }
             chop $ret;
             length $ret ? $ret : 'none'
            },
           },

          'border-collapse' => {
            format => 'collapse | separate',
            inherit => 1,
            default => 'separate',
           },

          'border-color' => {
            format => '(<colour>)[(<colour>)[(<colour>)(<colour>)?]?]?',
            properties => {
             'border-top-color' => [1],
             'border-right-color' => [2,1],
             'border-bottom-color' => [3,1],
             'border-left-color' => [4,2,1],
            },
            serialise => sub {
              my $p = shift;
              my @vals = map $p->{"border-$_-color"},
                             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 " ", @vals;
            },
           },

          'border-spacing' => {
            format => '<length> <length>?',
            default => '0',
            inherit => 1,
           },

          'border-style' => {
            format => "(none|hidden|dotted|dashed|solid|double|groove|ridge|
                        inset|outset)
                       [ (none|hidden|dotted|dashed|solid|double|groove|
                          ridge|inset|outset)
                         [ (none|hidden|dotted|dashed|solid|double|groove|
                            ridge|inset|outset)
                           (none|hidden|dotted|dashed|solid|double|groove|
                            ridge|inset|outset)?
                         ]?
                       ]?",
            properties => {
             'border-top-style' => [1],
             'border-right-style' => [2,1],
             'border-bottom-style' => [3,1],
             'border-left-style' => [4,2,1],
            },
            serialise => sub {
              my $p = shift;
              my @vals = map $p->{"border-$_-style"},
                             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 $_||'none', @vals;
            },
           },

          'border-top' => {
            format => "'border-top-width' || 'border-top-style' ||
                       'border-top-color'",
            serialise => sub {
              my $p = shift;
              my $ret = '';
              for(qw/ width style color /) {
                length $p->{"border-top-$_"}
                  and $ret .= $p->{"border-top-$_"}." ";
              }
              chop $ret;
              $ret
            },
           },
          'border-right' => {
            format => "'border-right-width' || 'border-right-style' ||
                       'border-right-color'",
            serialise => sub {
              my $p = shift;
              my $ret = '';
              for(qw/ width style color /) {
                length $p->{"border-right-$_"}
                  and $ret .= $p->{"border-right-$_"}." ";
              }
              chop $ret;
              $ret
            },
           },
          'border-bottom' => {
            format => "'border-bottom-width' || 'border-bottom-style' ||
                       'border-bottom-color'",
            serialise => sub {
              my $p = shift;
              my $ret = '';
              for(qw/ width style color /) {
                length $p->{"border-bottom-$_"}
                  and $ret .= $p->{"border-bottom-$_"}." ";
              }
              chop $ret;
              $ret
            },
           },
          'border-left' => {
            format => "'border-left-width' || 'border-left-style' ||
                       'border-left-color'",
            serialise => sub {
              my $p = shift;
              my $ret = '';
              for(qw/ width style color /) {
                length $p->{"border-left-$_"}
                  and $ret .= $p->{"border-left-$_"}." ";
              }
              chop $ret;
              $ret
            },
           },

          'border-top-color' => {
            format => '<colour>',
            default => "",
            inherit => 0,
           },
          'border-right-color' => {
            format => '<colour>',
            default => "",
            inherit => 0,
           },
          'border-bottom-color' => {
            format => '<colour>',
            default => "",
            inherit => 0,
           },
          'border-left-color' => {
            format => '<colour>',
            default => "",
            inherit => 0,
           },

          'border-top-style' => {
            format => 'none|hidden|dotted|dashed|solid|double|groove|ridge|
                       inset|outset',
            default => 'none',
            inherit => 0,
           },
          'border-right-style' => {
            format => 'none|hidden|dotted|dashed|solid|double|groove|ridge|
                       inset|outset',
            default => 'none',
            inherit => 0,
           },
          'border-bottom-style' => {
            format => 'none|hidden|dotted|dashed|solid|double|groove|ridge|
                       inset|outset',
            default => 'none',
            inherit => 0,
           },
          'border-left-style' => {
            format => 'none|hidden|dotted|dashed|solid|double|groove|ridge|
                       inset|outset',
            default => 'none',
            inherit => 0,
           },

          'border-top-width' => {
            format => '<length>|thin|thick|medium',
            default => 'medium',
            inherit => 0,
           },
          'border-right-width' => {
            format => '<length>|thin|thick|medium',
            default => 'medium',
            inherit => 0,
           },
          'border-bottom-width' => {
            format => '<length>|thin|thick|medium',
            default => 'medium',
            inherit => 0,
           },
          'border-left-width' => {
            format => '<length>|thin|thick|medium',
            default => 'medium',
            inherit => 0,
           },

          'border-width' => {
            format => "(<length>|thin|thick|medium)
                       [ (<length>|thin|thick|medium)
                         [ (<length>|thin|thick|medium)
                           (<length>|thin|thick|medium)?
                         ]?
                       ]?",
            properties => {
             'border-top-width' => [1],
             'border-right-width' => [2,1],
             'border-bottom-width' => [3,1],
             'border-left-width' => [4,2,1],
            },
            serialise => sub {
              my $p = shift;
              my @vals = map $p->{"border-$_-width"},
                             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 length $_ ? $_ : 'medium', @vals;
            },
           },

           border => {
            format => "(<length>|thin|thick|medium) ||
                       (none|hidden|dotted|dashed|solid|double|groove|ridge|
                        inset|outset) || (<colour>)",
            properties => {
             'border-top-width' => [1],
             'border-right-width' => [1],
             'border-bottom-width' => [1],
             'border-left-width' => [1],
             'border-top-style' => [2],
             'border-right-style' => [2],
             'border-bottom-style' => [2],
             'border-left-style' => [2],
             'border-top-color' => [3],
             'border-right-color' => [3],
             'border-bottom-color' => [3],
             'border-left-color' => [3],
            },
            serialise => sub {
              my $p = shift;
              my $ret = '';
              for(qw/ width style color /) {
                my $temp = $p->{"border-top-$_"};
                for my $side(qw/ right bottom left /) {
                  $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,
           },

           clear => {
            format => 'none|left|right|both',
            default => 'none',
            inherit => 0,
           },

           clip => {
            format => '<shape>|auto',
            default => 'auto',
            inherit => 0,
           },

           color => {
            format => '<colour>',
            default => 'rgba(0,0,0,1)',
            inherit => 1,
           },

           content => {
            format => '( normal|none|open-quote|close-quote|no-open-quote|
                         no-close-quote|<string>|<url>|<counter>|<attr> )+',
            default => 'normal',
            inherit => 0,
            list => 1,
           },

          'counter-increment' => {
            format => '[(<identifier>) (<integer>)? ]+ | none',
            default => 'none',
            inherit => 0,
            list => 1,
           },
          'counter-reset' => {
            format => '[(<identifier>) (<integer>)? ]+ | none',
            default => 'none',
            inherit => 0,
            list => 1,
           },

          'cue-after' => {
            format => '<url>|none',
            default => 'none',
            inherit => 0,
           },
          'cue-before' => {
            format => '<url>|none',
            default => 'none',
            inherit => 0,
           },

           cue =>{
            format => '(<url>|none) (<url>|none)?',
            properties => {
             'cue-before' => [1],
             'cue-after' => [2,1],
            },
            serialise => sub {
              my $p = shift;
              my @vals = @$p{"cue-before", "cue-after"};
              $vals[1] eq $vals[0] and pop @vals;
              return join " ", map length $_ ? $_ : 'none', @vals;
            },
           },

           cursor => {
            format => '[(<url>) ,]*
                       (auto|crosshair|default|pointer|move|e-resize|
                        ne-resize|nw-resize|n-resize|se-resize|sw-resize|
                        s-resize|w-resize|text|wait|help|progress)',
            default => 'auto',
            inherit => 1,
            list => 1,
           },

           direction => {
            format => 'ltr|rtl',
            default => 'ltr',
            inherit => 1,
           },

           display => {
            format => 'inline|block|list-item|run-in|inline-block|table|
                       inline-table|table-row-group|table-header-group|
                       table-footer-group|table-row|table-column-group|
                       table-column|table-cell|table-caption|none',
            default => 'inline',
            inherit => 0,
           },

           elevation => {
            format => '<angle>|below|level|above|higher|lower',
            default => '0',
            inherit => 1,
           },

          'empty-cells' => {
            format => 'show|hide',
            default => 'show',
            inherit => 1,
           },

           float => {
            format => 'left|right|none',
            default => 'none',
            inherit => 0,
           },

          'font-family' => { # aka typeface
            format => '(serif|sans-serif|cursive|fantasy|monospace|
                        <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,
           },

          'font-variant' => {
            format => 'normal | small-caps',
            default => 'normal',
            inherit => 1,
           },

          'font-weight' => {
            format => 'normal|bold|bolder|lighter|
                       100|200|300|400|500|600|700|800|900',
            default => 'normal',
            inherit => 1,
           },

           font => {
            format => "[ 'font-style' || 'font-variant' || 'font-weight' ]?
                       'font-size' [ / 'line-height' ]? 'font-family'",
            special_values => {
              caption => '13px Lucida Grande, sans-serif',
              icon => '13px Lucida Grande, sans-serif',
              menu => '13px Lucida Grande, sans-serif',
             'message-box' => '13px Lucida Grande, sans-serif',
             'small-caption' => '11px Lucida Grande, sans-serif',
             'status-bar' => '10px Lucida Grande, sans-serif',
            },
            serialise => sub {
              my $p = shift;
              my $ret = '';
              for(qw/ style variant weight /) {
                length $p->{"font-$_"}
                  and $ret .= $p->{"font-$_"}." ";
              }
              $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,
           },

          'list-style-position' => {
            format => 'inside|outside',
            default => 'outside',
            inherit => 1,
           },

          'list-style-type' => {
            format => 'disc|circle|square|decimal|decimal-leading-zero|
                       lower-roman|upper-roman|lower-greek|lower-latin|
                       upper-latin|armenian|georgian|lower-alpha|
                       upper-alpha',
            default => 'disc',
            inherit => 1,
           },

          'list-style' => {
            format => "'list-style-type'||'list-style-position'||
                       'list-style-image'",
            serialise => sub {
              my $p = shift;
              my $ret = '';
              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,
           },

          'outline-color' => {
            format => '<colour>|invert',
            default => 'invert',
            inherit => 0,
           },

          'outline-style' => {
            format => 'none|hidden|dotted|dashed|solid|double|groove|ridge|
                       inset|outset',
            default => 'none',
            inherit => 0,
           },

          'outline-width' => {
            format => '<length>|thin|thick|medium',
            default => 'medium',
            inherit => 0,
           },

           outline => {
            format => "'outline-color'||'outline-style'||'outline-width'",
            serialise => sub {
              my $p = shift;
              my $ret = '';
              for(qw/ color style width /) {
                length $p->{"outline-$_"}
                  and $ret .= $p->{"outline-$_"}." ";
              }
              chop $ret;
              length $ret ? $ret : 'invert';
            },
           },

           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;
              my @vals = map $p->{"padding-$_"},
                             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;
            },
           },

          'page-break-after' => {
            format => 'auto|always|avoid|left|right',
            default => 'auto',
            inherit => 0,
           },
          'page-break-before' => {
            format => 'auto|always|avoid|left|right',
            default => 'auto',
            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,
           },

           pitch => {
            format => '<frequency>|x-low|low|medium|high|x-high',
            default => 'medium',
            inherit => 1,
           },

          'play-during' => {
             format => '<url> [ mix || repeat ]? | auto | none',
             default => 'auto',
             inherit => 0,
           },

           position => {
            format => 'static|relative|absolute|fixed',
            default => 'relative',
            inherit => 0,
           },

           quotes => {
            format => '[(<string>)(<string>)]+|none',
            default => 'none',
            inherit => 1,
            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,
           },

          'speak-numeral' => {
            format => 'digits|continuous',
            default => 'continuous',
            inherit => 1,
           },

          'speak-punctuation' => {
            format => 'code|none',
            default => 'none',
            inherit => 1,
           },

           speak => {
            format => 'normal|none|spell-out',
            default => 'normal',
            inherit => 1,
           },

          'speech-rate' => {
            format => '<number>|x-slow|slow|medium|fast|x-fast|faster|slower',
            default => 'medium',
            inherit => 1,
           },

           stress => {
            format => '<number>',
            default => 50,
            inherit => 1,
           },

          'table-layout' => {
            format => 'auto|fixed',
            default => 'auto',
            inherit => 0,
           },

          'text-align' => {
            format => 'left|right|center|justify|auto',
            default => 'auto',
            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,
           },

          'z-index' => {
            format => 'auto|<integer>',
            default => 'auto',
            inherit => 0,
           },
         );
         $CSS21->add_property( $_ => $properties{$_} ) for keys %properties;

SEE ALSO

       CSS::DOM