/[suikacvs]/markup/html/whatpm/Whatpm/CSS/Cascade.pm
Suika

Diff of /markup/html/whatpm/Whatpm/CSS/Cascade.pm

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 1.1 by wakaba, Mon Dec 31 13:47:49 2007 UTC revision 1.11 by wakaba, Mon Jan 14 11:21:22 2008 UTC
# Line 1  Line 1 
1  package Whatpm::CSS::Cascade;  package Whatpm::CSS::Cascade;
2    use strict;
3    
4  require Whatpm::CSS::Parser; ## NOTE: For property definitions.  require Whatpm::CSS::Parser; ## NOTE: For property definitions.
5  require Whatpm::CSS::SelectorsSerializer;  require Whatpm::CSS::SelectorsSerializer;
# Line 9  use Scalar::Util qw/refaddr/; Line 10  use Scalar::Util qw/refaddr/;
10  sub new ($$) {  sub new ($$) {
11    my $self = bless {style_sheets => []}, shift;    my $self = bless {style_sheets => []}, shift;
12    $self->{document} = shift;    $self->{document} = shift;
13    
14      ## Device dependent font size parameters
15      my @scale = (3/5, 3/4, 8/9, 1, 6/5, 3/2, 2/1, 3/1); ## From css3-fonts
16      $self->{font_size}->[$_] = 16 * $scale[$_] for 0..$#scale;
17      ## TODO: Provide better default
18      $self->{get_smaller_font_size} = sub ($$) {
19        #my ($self, $original_px) = @_;
20        return $_[1] / 1.1;
21      };
22      ## TODO: Provide better default
23      $self->{get_larger_font_size} = sub ($$) {
24        #my ($self, $original_px) = @_;
25        return $_[1] * 1.1;
26      };
27      ## $self->{has_invert}: Should be same as
28      ##     $parser->{prop_value}->{'outline-color'}->{invert}.
29    
30    return $self;    return $self;
31  } # new  } # new
32    
# Line 41  sub ___associate_rules ($) { Line 59  sub ___associate_rules ($) {
59      for my $rule (@{$sheet->css_rules}) {      for my $rule (@{$sheet->css_rules}) {
60        next if $rule->type != 1; # STYLE_RULE        next if $rule->type != 1; # STYLE_RULE
61    
62        my $selectors_str = Whatpm::CSS::SelectorsSerializer->serialize_test        my $elements_to_specificity = {};
63            ($$rule->{_selectors});  
64        unless ($selectors_to_elements->{$selectors_str}) {        for my $selector (@{$$rule->{_selectors}}) {
65          $selectors_to_elements->{$selectors_str}          my $selector_str = Whatpm::CSS::SelectorsSerializer->serialize_test
66              = $self->{document}->___query_selector_all ($$rule->{_selectors});              ([$selector]);
67            unless ($selectors_to_elements->{$selector_str}) {
68              $selectors_to_elements->{$selector_str}
69                  = $self->{document}->___query_selector_all ([$selector]);
70            }
71            next unless @{$selectors_to_elements->{$selector_str}};
72    
73            my $selector_specificity
74                = Whatpm::CSS::SelectorsParser->get_selector_specificity
75                    ($selector);
76            for (@{$selectors_to_elements->{$selector_str}}) {
77              my $current_specificity = $elements_to_specificity->{refaddr $_};
78              if (not defined $current_specificity or ## "*"-only case.
79                  $selector_specificity->[0] > $current_specificity->[0] or
80                  $selector_specificity->[1] > $current_specificity->[1] or
81                  $selector_specificity->[2] > $current_specificity->[2] or
82                  $selector_specificity->[3] > $current_specificity->[3]) {
83                $elements_to_specificity->{refaddr $_} = $selector_specificity;
84              }
85            }
86          }
87    
88          my $sd = $rule->style;
89          for (keys %$elements_to_specificity) {
90            push @{$self->{element_to_sds}->{$_} ||= []},
91                [$sd, $elements_to_specificity->{$_}];
92        }        }
         
       push @{$self->{element_to_sd}->{refaddr $_} ||= []}, $rule->style  
           for @{$selectors_to_elements->{$selectors_str}};  
       ## TODO: specificity  
93      }      }
94    }    }
95    
96      for my $eid (keys %{$self->{element_to_sds} or {}}) {
97        $self->{element_to_sds}->{$eid} = [sort {
98          $a->[1]->[0] <=> $b->[1]->[0] or
99          $a->[1]->[1] <=> $b->[1]->[1] or
100          $a->[1]->[2] <=> $b->[1]->[2] or
101          $a->[1]->[3] <=> $b->[1]->[3]
102          ## NOTE: Perl |sort| is stable.
103        } @{$self->{element_to_sds}->{$eid} or []}];
104      }
105  } # associate_rules  } # associate_rules
106    
107  sub get_cascaded_value ($$$) {  sub get_cascaded_value ($$$) {
# Line 61  sub get_cascaded_value ($$$) { Line 109  sub get_cascaded_value ($$$) {
109    return undef unless $Whatpm::CSS::Parser::Prop->{$prop_name};    return undef unless $Whatpm::CSS::Parser::Prop->{$prop_name};
110    
111    my $key = $Whatpm::CSS::Parser::Prop->{$prop_name}->{key};    my $key = $Whatpm::CSS::Parser::Prop->{$prop_name}->{key};
112      return undef unless defined $key; ## Shorthand property or some.
113    
114    ## TODO: cascading order    my $value;
115    for my $sd (reverse @{$self->{element_to_sd}->{refaddr $element} or []}) {    for my $sds (reverse @{$self->{element_to_sds}->{refaddr $element} or []}) {
116      my $vp = $$sd->{$key};      my $vp = ${$sds->[0]}->{$key};
117      return $vp->[0] if defined $vp;      if ($vp->[1] eq 'important') {
118          return $vp->[0];
119        } else {
120          $value = $vp->[0] unless defined $value;
121        }
122    }    }
123    
124    return undef;    return $value; # might be |undef|.
125  } # get_cascaded_value  } # get_cascaded_value
126    
127    sub get_specified_value ($$$) {
128      my ($self, $element, $prop_name) = @_;
129    
130      ## TODO: Remove {specified_value} caching, once we implement most
131      ## of CSS 2.1 properties and confirm that it makes almost non sence
132      ## because of its duplication with {computed_value} caching.
133    
134      ## NOTE: |top| computation refers |bottom| and vice versa.
135      ## |left| does |right| and vice versa.
136    
137      my $eid = refaddr $element;
138      unless (exists $self->{specified_value}->{$eid}->{$prop_name}) {
139        my $cascaded = $self->get_cascaded_value ($element, $prop_name);
140        $self->{specified_value}->{$eid}->{$prop_name} = $cascaded;
141        
142        unless (defined $cascaded) {
143          my $prop_def = $Whatpm::CSS::Parser::Prop->{$prop_name};
144          if (defined $prop_def) {
145            if ($prop_def->{inherited}) {
146              my $parent_element = $element->manakai_parent_element;
147              if (defined $parent_element) {
148                $self->{specified_value}->{$eid}->{$prop_name}
149                    = $self->get_computed_value ($parent_element, $prop_name);
150              } else {
151                $self->{specified_value}->{$eid}->{$prop_name}
152                    = $prop_def->{initial};
153              }
154            } else {
155              $self->{specified_value}->{$eid}->{$prop_name}
156                  = $prop_def->{initial};
157            }
158          } else {
159            $self->{specified_value}->{$eid}->{$prop_name} = undef;
160          }
161        }
162      }
163    
164      ## NOTE: Always |undef| for shorthand properties.
165    
166      return $self->{specified_value}->{$eid}->{$prop_name};
167    } # get_specified_value
168    
169    sub get_specified_value_no_inherit ($$$) {
170      my ($self, $element, $prop_name) = @_;
171    
172      my $specified = $self->get_specified_value ($element, $prop_name);
173      if (defined $specified and $specified->[0] eq 'INHERIT') {
174        ## ISSUE: CSS 2.1 does not say to resolve computed value of the parent.
175        ## However, it is necessary for some cases (see
176        ## <http://suika.fam.cx/gate/2005/sw/inherit>).  In addition,
177        ## the initial value is not a computed value for some properties.
178        my $parent_element = $element->manakai_parent_element;
179        if (defined $parent_element) {
180          $specified = $self->get_computed_value ($parent_element, $prop_name);
181        } else {
182          my $prop_def = $Whatpm::CSS::Parser::Prop->{$prop_name};
183          $specified = $prop_def->{initial};
184        }
185        ## NOTE: Because of this handling, {compute} codes must be
186        ## idempotent.
187      }
188      return $specified;
189    } # get_specified_value_no_inherit
190    
191    sub get_computed_value ($$$) {
192      my ($self, $element, $prop_name) = @_;
193    
194      my $eid = refaddr $element;
195      unless (exists $self->{computed_value}->{$eid}->{$prop_name}) {
196        my $prop_def = $Whatpm::CSS::Parser::Prop->{$prop_name};
197        if (defined $prop_def) {
198          if ($prop_def->{compute_multiple}) {
199            $prop_def->{compute_multiple}->($self, $element, $eid, $prop_name);
200          } else {
201            my $specified = $self->get_specified_value_no_inherit
202                ($element, $prop_name);
203            $self->{computed_value}->{$eid}->{$prop_name}
204                = $prop_def->{compute}->($self, $element, $prop_name, $specified);
205          }
206        } else {
207          $self->{computed_value}->{$eid}->{$prop_name} = undef;
208        }
209      }
210    
211      ## NOTE: Always |undef| for shorthand properties.
212    
213      return $self->{computed_value}->{$eid}->{$prop_name};
214    } # get_computed_value
215    
216  1;  1;
217  ## $Date$  ## $Date$

Legend:
Removed from v.1.1  
changed lines
  Added in v.1.11

admin@suikawiki.org
ViewVC Help
Powered by ViewVC 1.1.24