/[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.8 - (hide annotations) (download)
Thu Jan 3 08:37:22 2008 UTC (16 years, 10 months ago) by wakaba
Branch: MAIN
Changes since 1.7: +16 -1 lines
++ whatpm/Whatpm/CSS/ChangeLog	3 Jan 2008 08:36:47 -0000
2008-01-03  Wakaba  <wakaba@suika.fam.cx>

	* Parser.pm: 'font-size' support.

	* Cascade.pm (new): Set default value for 'font-size'
	relative- and absolute- value computations.

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

admin@suikawiki.org
ViewVC Help
Powered by ViewVC 1.1.24