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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.3 - (hide annotations) (download)
Tue Jan 1 07:07:28 2008 UTC (16 years, 10 months ago) by wakaba
Branch: MAIN
Changes since 1.2: +61 -1 lines
++ whatpm/Whatpm/CSS/ChangeLog	1 Jan 2008 07:07:18 -0000
	* Cascade.pm (get_cascaded_value): It now should return |undef|
	for shorthand properties.
	(get_specified_value, get_computed_value): New methods.

	* Parser.pm: |initial|, |inherited|, and |compute| properties
	are added to property definitions.

2008-01-01  Wakaba  <wakaba@suika.fam.cx>

1 wakaba 1.1 package Whatpm::CSS::Cascade;
2    
3     require Whatpm::CSS::Parser; ## NOTE: For property definitions.
4     require Whatpm::CSS::SelectorsSerializer;
5     use Scalar::Util qw/refaddr/;
6    
7     ## Cascading and value computations
8    
9     sub new ($$) {
10     my $self = bless {style_sheets => []}, shift;
11     $self->{document} = shift;
12     return $self;
13     } # new
14    
15     ## NOTE: This version does not support dynamic addition --- style
16     ## sheets must be added before any other operation.
17     ## NOTE: The $ss argument must be a value that can be interpreted as
18     ## an array reference of CSSStyleSheet objects.
19     ## NOTE: |type| and |media| attributes are not accounted by this
20     ## method (and any others in the class); CSSStyleSheet objects must
21     ## be filtered before they are passed to this method.
22     sub add_style_sheets ($$) {
23     my ($self, $ss) = @_;
24    
25     push @{$self->{style_sheets}}, @$ss;
26     } # add_style_sheets
27    
28     ## TODO: non-CSS presentation hints
29     ## TODO: style=""
30    
31     sub ___associate_rules ($) {
32     my $self = shift;
33    
34     my $selectors_to_elements;
35    
36     for my $sheet (@{$self->{style_sheets}}) {
37     ## TODO: @media
38     ## TODO: @import
39     ## TODO: style sheet sources
40    
41     for my $rule (@{$sheet->css_rules}) {
42     next if $rule->type != 1; # STYLE_RULE
43    
44 wakaba 1.2 my $elements_to_specificity = {};
45    
46     for my $selector (@{$$rule->{_selectors}}) {
47     my $selector_str = Whatpm::CSS::SelectorsSerializer->serialize_test
48     ([$selector]);
49     unless ($selectors_to_elements->{$selector_str}) {
50     $selectors_to_elements->{$selector_str}
51     = $self->{document}->___query_selector_all ([$selector]);
52     }
53     next unless @{$selectors_to_elements->{$selector_str}};
54    
55     my $selector_specificity
56     = Whatpm::CSS::SelectorsParser->get_selector_specificity
57     ($selector);
58     for (@{$selectors_to_elements->{$selector_str}}) {
59     my $current_specificity = $elements_to_specificity->{refaddr $_};
60     if ($selector_specificity->[0] > $current_specificity->[0] or
61     $selector_specificity->[1] > $current_specificity->[1] or
62     $selector_specificity->[2] > $current_specificity->[2] or
63     $selector_specificity->[3] > $current_specificity->[3]) {
64     $elements_to_specificity->{refaddr $_} = $selector_specificity;
65     }
66     }
67     }
68    
69     my $sd = $rule->style;
70     for (keys %$elements_to_specificity) {
71     push @{$self->{element_to_sds}->{$_} ||= []},
72     [$sd, $elements_to_specificity->{$_}];
73 wakaba 1.1 }
74     }
75     }
76    
77 wakaba 1.2 for my $eid (keys %{$self->{element_to_sds} or {}}) {
78     $self->{element_to_sds}->{$eid} = [sort {
79     $a->[1]->[0] <=> $b->[1]->[0] or
80     $a->[1]->[1] <=> $b->[1]->[1] or
81     $a->[1]->[2] <=> $b->[1]->[2] or
82     $a->[1]->[3] <=> $b->[1]->[3]
83     ## NOTE: Perl |sort| is stable.
84     } @{$self->{element_to_sds}->{$eid} or []}];
85     }
86 wakaba 1.1 } # associate_rules
87    
88     sub get_cascaded_value ($$$) {
89     my ($self, $element, $prop_name) = @_;
90     return undef unless $Whatpm::CSS::Parser::Prop->{$prop_name};
91    
92     my $key = $Whatpm::CSS::Parser::Prop->{$prop_name}->{key};
93 wakaba 1.3 return undef unless defined $key; ## Shorthand property or some.
94 wakaba 1.1
95 wakaba 1.2 my $value;
96     for my $sds (reverse @{$self->{element_to_sds}->{refaddr $element} or []}) {
97     my $vp = ${$sds->[0]}->{$key};
98     if (defined $vp->[1] and $vp->[1] eq 'important') {
99     return $vp->[0];
100     } else {
101     $value = $vp->[0] unless defined $value;
102     }
103 wakaba 1.1 }
104    
105 wakaba 1.2 return $value; # might be |undef|.
106 wakaba 1.1 } # get_cascaded_value
107    
108 wakaba 1.3 sub get_specified_value ($$$) {
109     my ($self, $element, $prop_name) = @_;
110    
111     ## TODO: Remove {specified_value} caching, once we implement most
112     ## of CSS 2.1 properties and confirm that it makes almost non sence
113     ## because of its duplication with {computed_value} caching.
114    
115     my $eid = refaddr $element;
116     unless (exists $self->{specified_value}->{$eid}->{$prop_name}) {
117     my $cascaded = $self->get_cascaded_value ($element, $prop_name);
118     $self->{specified_value}->{$eid}->{$prop_name} = $cascaded;
119    
120     unless (defined $cascaded) {
121     my $prop_def = $Whatpm::CSS::Parser::Prop->{$prop_name};
122     if (defined $prop_def) {
123     if ($prop_def->{inherited}) {
124     my $parent_element = $element->manakai_parent_element;
125     if (defined $parent_element) {
126     $self->{specified_value}->{$eid}->{$prop_name}
127     = $self->get_computed_value ($parent_element, $prop_name);
128     } else {
129     $self->{specified_value}->{$eid}->{$prop_name}
130     = $prop_def->{initial};
131     }
132     } else {
133     $self->{specified_value}->{$eid}->{$prop_name}
134     = $prop_def->{initial};
135     }
136     } else {
137     $self->{specified_value}->{$eid}->{$prop_name} = undef;
138     }
139     }
140     }
141    
142     ## NOTE: Always |undef| for shorthand properties.
143    
144     return $self->{specified_value}->{$eid}->{$prop_name};
145     } # get_specified_value
146    
147     sub get_computed_value ($$$) {
148     my ($self, $element, $prop_name) = @_;
149    
150     my $eid = refaddr $element;
151     unless (exists $self->{computed_value}->{$eid}->{$prop_name}) {
152     my $prop_def = $Whatpm::CSS::Parser::Prop->{$prop_name};
153     if (defined $prop_def) {
154     $self->{computed_value}->{$eid}->{$prop_name}
155     = $prop_def->{compute}->($self, $element, $prop_name,
156     $self->get_specified_value
157     ($element, $prop_name));
158     } else {
159     $self->{computed_value}->{$eid}->{$prop_name} = undef;
160     }
161     }
162    
163     ## NOTE: Always |undef| for shorthand properties.
164    
165     return $self->{computed_value}->{$eid}->{$prop_name};
166     } # get_computed_value
167 wakaba 1.1
168     1;
169 wakaba 1.3 ## $Date: 2008/01/01 02:54:35 $

admin@suikawiki.org
ViewVC Help
Powered by ViewVC 1.1.24