/[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.10 - (show annotations) (download)
Sun Jan 6 14:15:36 2008 UTC (16 years, 10 months ago) by wakaba
Branch: MAIN
Changes since 1.9: +3 -1 lines
++ whatpm/Whatpm/CSS/ChangeLog	6 Jan 2008 14:15:24 -0000
	* Cascade.pm: The object now has new device-dependent
	parameter, |has_invert|.

	* Parser.pm: The object now has new device-dependent
	parameter, |clip_color| function.
	(parse_char_string): Inifinite-loop fixed for ignoring
	states.  No longer check for '(' and '[' matchings for
	compatibility with browsers.
	($default_serializer): Support for 'RGBA' data type.
	(color): Reimplemented.
	(backbround-color, border-top-color, border-right-color,
	border-bottom-color, border-left-color, outline-color): Implemented.

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

1 package Whatpm::CSS::Cascade;
2 use strict;
3
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
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;
31 } # new
32
33 ## NOTE: This version does not support dynamic addition --- style
34 ## sheets must be added before any other operation.
35 ## NOTE: The $ss argument must be a value that can be interpreted as
36 ## an array reference of CSSStyleSheet objects.
37 ## NOTE: |type| and |media| attributes are not accounted by this
38 ## method (and any others in the class); CSSStyleSheet objects must
39 ## be filtered before they are passed to this method.
40 sub add_style_sheets ($$) {
41 my ($self, $ss) = @_;
42
43 push @{$self->{style_sheets}}, @$ss;
44 } # add_style_sheets
45
46 ## TODO: non-CSS presentation hints
47 ## TODO: style=""
48
49 sub ___associate_rules ($) {
50 my $self = shift;
51
52 my $selectors_to_elements;
53
54 for my $sheet (@{$self->{style_sheets}}) {
55 ## TODO: @media
56 ## TODO: @import
57 ## TODO: style sheet sources
58
59 for my $rule (@{$sheet->css_rules}) {
60 next if $rule->type != 1; # STYLE_RULE
61
62 my $elements_to_specificity = {};
63
64 for my $selector (@{$$rule->{_selectors}}) {
65 my $selector_str = Whatpm::CSS::SelectorsSerializer->serialize_test
66 ([$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 }
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
106
107 sub get_cascaded_value ($$$) {
108 my ($self, $element, $prop_name) = @_;
109 return undef unless $Whatpm::CSS::Parser::Prop->{$prop_name};
110
111 my $key = $Whatpm::CSS::Parser::Prop->{$prop_name}->{key};
112 return undef unless defined $key; ## Shorthand property or some.
113
114 my $value;
115 for my $sds (reverse @{$self->{element_to_sds}->{refaddr $element} or []}) {
116 my $vp = ${$sds->[0]}->{$key};
117 if (defined $vp->[1] and $vp->[1] eq 'important') {
118 return $vp->[0];
119 } else {
120 $value = $vp->[0] unless defined $value;
121 }
122 }
123
124 return $value; # might be |undef|.
125 } # 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;
217 ## $Date: 2008/01/03 13:51:41 $

admin@suikawiki.org
ViewVC Help
Powered by ViewVC 1.1.24