/[suikacvs]/messaging/manakai/lib/Message/DOM/CSSStyleDeclaration.pm
Suika

Contents of /messaging/manakai/lib/Message/DOM/CSSStyleDeclaration.pm

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.15 - (show annotations) (download)
Sat Feb 2 13:58:02 2008 UTC (16 years, 9 months ago) by wakaba
Branch: MAIN
Changes since 1.14: +95 -8 lines
++ manakai/lib/Message/DOM/ChangeLog	2 Feb 2008 13:57:59 -0000
2008-02-02  Wakaba  <wakaba@suika.fam.cx>

	* CSSStyleDeclaration.pm ($serialize_value): New (was
	part of Whatpm::CSS::Parser as $default_serializer).
	Use it instead of old 'serialize' parameter of CSS
	property definition.

1 package Message::DOM::CSSStyleDeclaration;
2 use strict;
3 our $VERSION=do{my @r=(q$Revision: 1.14 $=~/\d+/g);sprintf "%d."."%02d" x $#r,@r};
4 push our @ISA, 'Message::IF::CSSStyleDeclaration',
5 'Message::IF::CSS2Properties';
6
7 my $serialize_value = sub ($$$) {
8 my ($self, $prop_name, $value) = @_;
9 if ($value->[0] eq 'NUMBER' or $value->[0] eq 'WEIGHT') {
10 ## TODO: What we currently do for 'font-weight' is different from
11 ## any browser for lighter/bolder cases. We need to fix this, but
12 ## how?
13 return $value->[1]; ## TODO: big or small number cases?
14 } elsif ($value->[0] eq 'DIMENSION') {
15 return $value->[1] . $value->[2]; ## NOTE: This is what browsers do.
16 } elsif ($value->[0] eq 'PERCENTAGE') {
17 return $value->[1] . '%';
18 } elsif ($value->[0] eq 'KEYWORD') {
19 return $value->[1];
20 } elsif ($value->[0] eq 'URI') {
21 ## NOTE: This is what browsers do.
22 return 'url('.$value->[1].')';
23 } elsif ($value->[0] eq 'RGBA') {
24 if ($value->[4] == 1) {
25 return 'rgb('.$value->[1].', '.$value->[2].', '.$value->[3].')';
26 } elsif ($value->[4] == 0) {
27 ## TODO: check what browsers do...
28 return 'transparent';
29 } else {
30 return 'rgba('.$value->[1].', '.$value->[2].', '.$value->[3].', '
31 .$value->[4].')';
32 }
33 } elsif ($value->[0] eq 'INHERIT') {
34 return 'inherit';
35 } elsif ($value->[0] eq 'DECORATION') {
36 my @v = ();
37 push @v, 'underline' if $value->[1];
38 push @v, 'overline' if $value->[2];
39 push @v, 'line-through' if $value->[3];
40 push @v, 'blink' if $value->[4];
41 return 'none' unless @v;
42 return join ' ', @v;
43 } elsif ($value->[0] eq 'QUOTES') {
44 return join ' ', map {'"'.$_.'"'} map {$_->[0], $_->[1]} @{$value->[1]};
45 ## NOTE: The result string might not be a <'quotes'> if it contains
46 ## e.g. '"'. In addition, it might not be a <'quotes'> if
47 ## @{$value->[1]} is empty (which is unlikely as long as the implementation
48 ## is not broken).
49 } elsif ($value->[0] eq 'CONTENT') {
50 return join ' ', map {
51 $_->[0] eq 'KEYWORD' ? $_->[1] :
52 $_->[0] eq 'STRING' ? '"' . $_->[1] . '"' :
53 $_->[0] eq 'URI' ? 'url(' . $_->[1] . ')' :
54 $_->[0] eq 'ATTR' ? 'attr(' . $_->[2] . ')' : ## TODO: prefix
55 $_->[0] eq 'COUNTER' ? 'counter(' . $_->[1] . ', ' . $_->[3] . ')' :
56 $_->[0] eq 'COUNTERS' ? 'counters(' . $_->[1] . ', "' . $_->[2] . '", ' . $_->[3] . ')' :
57 ''
58 } @{$value}[1..$#$value];
59 } elsif ($value->[0] eq 'RECT') {
60 ## NOTE: Four components are DIMENSIONs.
61 return 'rect(' . $value->[1]->[1].$value->[1]->[2] . ', '
62 . $value->[2]->[1].$value->[2]->[2] . ', '
63 . $value->[3]->[1].$value->[3]->[2] . ', '
64 . $value->[4]->[1].$value->[4]->[2] . ')';
65 } elsif ($value->[0] eq 'SETCOUNTER' or $value->[0] eq 'ADDCOUNTER') {
66 return join ' ', map {$_->[0], $_->[1]} @$value[1..$#$value];
67 } elsif ($value->[0] eq 'FONT') {
68 return join ', ', map {
69 if ($_->[0] eq 'STRING') {
70 '"'.$_->[1].'"'; ## NOTE: This is what Firefox does.
71 } elsif ($_->[0] eq 'KEYWORD') {
72 $_->[1]; ## NOTE: This is what Firefox does.
73 } else {
74 ## NOTE: This should be an error.
75 '""';
76 }
77 } @$value[1..$#$value];
78 } elsif ($value->[0] eq 'CURSOR') {
79 return join ', ', map {
80 if ($_->[0] eq 'URI') {
81 'url('.$_->[1].')'; ## NOTE: This is what Firefox does.
82 } elsif ($_->[0] eq 'KEYWORD') {
83 $_->[1];
84 } else {
85 ## NOTE: This should be an error.
86 '""';
87 }
88 } @$value[1..$#$value];
89 } else {
90 return '';
91 }
92 }; # $serialize_value
93
94 sub ____new ($) {
95 return bless \{}, $_[0];
96 } # ____new
97
98 sub AUTOLOAD {
99 my $method_name = our $AUTOLOAD;
100 $method_name =~ s/.*:://;
101 return if $method_name eq 'DESTROY';
102
103 require Whatpm::CSS::Parser;
104 my $prop_def = $Whatpm::CSS::Parser::Attr->{$method_name};
105
106 if ($prop_def) {
107 no strict 'refs';
108 if (defined $prop_def->{key}) {
109 *{ $method_name } = sub {
110 ## TODO: setter
111
112 my $self = $_[0];
113 my $value = $$self->{$prop_def->{key}};
114 if ($value) {
115 return $serialize_value->($self, $prop_def->{css}, $value->[0]);
116 } else {
117 return '';
118 }
119 };
120 } elsif ($prop_def->{serialize_shorthand} or
121 $prop_def->{serialize_multiple}) {
122 *{ $method_name } = sub {
123 ## TODO: setter
124
125 my $self = $_[0];
126 my $v = ($prop_def->{serialize_shorthand} or
127 $prop_def->{serialize_multiple})->($self);
128 if (defined $v->{$prop_def->{css}}) {
129 return $v->{$prop_def->{css}}->[0];
130 } else {
131 return '';
132 }
133 ## ISSUE: If one of shorthand component properties is !important?
134 };
135 } else {
136 die qq<Implementation error: Can't load serializer for "$AUTOLOAD">;
137 }
138 goto &{ $AUTOLOAD };
139 } else {
140 require Carp;
141 Carp::croak (qq<Can't locate method "$AUTOLOAD">);
142 }
143 } # AUTOLOAD
144
145 use overload
146 '@{}' => sub {
147 tie my @list, ref $_[0], $_[0];
148 return \@list;
149 },
150 fallback => 1;
151
152 sub TIEARRAY ($$) { $_[1] }
153
154 ## |CSSStyleDeclaration| attributes
155
156 sub css_text ($;$) {
157 ## TODO: setter
158
159 ## NOTE: Where and how white space characters are inserted are
160 ## intentionally changed from those in browsers so that properties are
161 ## more prettily printed.
162 ## See <http://suika.fam.cx/gate/2005/sw/cssText> for what browsers do.
163 ## TODO: Ordering issue.
164 require Whatpm::CSS::Parser;
165 my $self = $_[0];
166 my $r = '';
167 my %serialized;
168 for (sort {$a cmp $b} grep {$$self->{$_}} keys %$$self) {
169 my $prop_def = $Whatpm::CSS::Parser::Key->{$_};
170 next unless $prop_def;
171
172 if ($prop_def->{serialize_multiple}) {
173 unless ($serialized{$prop_def->{serialize_multiple}}) {
174 $serialized{$prop_def->{serialize_multiple}} = 1;
175 my $v = $prop_def->{serialize_multiple}->($self);
176 for my $prop_name (sort {$a cmp $b} keys %$v) {
177 $r .= ' ' . $prop_name . ': ' . $v->{$prop_name}->[0];
178 $r .= ' ! ' . $v->{$prop_name}->[1] if length $v->{$prop_name}->[1];
179 $r .= ";\n";
180 }
181 }
182 } else {
183 my $value = $$self->{$_};
184 my $s = $serialize_value->($self, $prop_def->{css}, $value->[0]);
185 if (length $s) {
186 $r .= ' ' . $prop_def->{css} . ': ' . $s;
187 $r .= ' ! ' . $value->[1] if length $value->[1];
188 $r .= ";\n";
189 }
190 }
191 }
192 return $r;
193 } # css_text
194
195 sub length ($) {
196 require Whatpm::CSS::Parser;
197 return scalar @{[grep {$_}
198 map { $Whatpm::CSS::Parser::Key->{$_} }
199 keys %${$_[0]}]->[$_[1]]};
200 } # length
201 *FETCHSIZE = \&length;
202
203 ## TODO: STORESIZE
204
205 sub parent_rule ($) {
206 return ${$_[0]}->{parent_rule};
207 } # parent_rule
208
209 ## |CSSStyleDeclaration| methods
210
211 sub get_property_priority ($$) {
212 my $prop_name = ''.$_[1];
213
214 require Whatpm::CSS::Parser;
215 my $prop_def = $Whatpm::CSS::Parser::Prop->{$prop_name};
216 return '' unless defined $prop_def;
217
218 if (defined $prop_def->{key}) {
219 my $v = ${$_[0]}->{$prop_def->{key}};
220 return $v ? $v->[1] : '';
221 } elsif ($prop_def->{serialize_shorthand} or
222 $prop_def->{serialize_multiple}) {
223 my $v = ($prop_def->{serialize_shorthand} or
224 $prop_def->{serialize_multiple})->($_[0]);
225 if (defined $v->{$prop_def->{css}}) {
226 return $v->{$prop_def->{css}}->[1];
227 } else {
228 return '';
229 }
230 } else {
231 die "Implementation error: No serializer for property '$prop_name'";
232 }
233 } # get_property_priority
234
235 sub item ($$) {
236 require Whatpm::CSS::Parser;
237 return '' if $_[1] < 0;
238 ## TODO: ordering (should be same as that in |css_text|.
239 my $v = [map {$_->{key}}
240 grep {$_}
241 map { $Whatpm::CSS::Parser::Key->{$_} }
242 keys %${$_[0]}]->[$_[1]];
243 return defined $v ? $v : '';
244 } # item
245 *FETCH = \&item;
246
247 ## TODO: STORE, DELETE
248
249 sub EXISTS ($$) {
250 return length $_[0]->item;
251 } # EXISTS
252
253 ## TODO: Implement other methods and attributes
254
255 package Message::DOM::CSSComputedStyleDeclaration;
256 push our @ISA, 'Message::IF::CSSStyleDeclaration',
257 'Message::IF::CSS2Properties';
258
259 sub ____new ($$$) {
260 my $self = bless \{}, shift;
261 $$self->{cascade} = shift; # Whatpm::CSS::Cascade object.
262 $$self->{element} = shift; ## TODO: This link should be weaken?
263 return $self;
264 } # ____new
265
266 sub AUTOLOAD {
267 my $method_name = our $AUTOLOAD;
268 $method_name =~ s/.*:://;
269 return if $method_name eq 'DESTROY';
270
271 require Whatpm::CSS::Parser;
272 my $prop_def = $Whatpm::CSS::Parser::Attr->{$method_name};
273
274 if ($prop_def) {
275 no strict 'refs';
276 if ($prop_def->{compute} or $prop_def->{compute_multiple}) {
277 *{ $method_name } = sub {
278 ## TODO: setter
279
280 my $self = $_[0];
281 my $value = $$self->{cascade}->get_computed_value
282 ($$self->{element}, $prop_def->{css});
283 if ($value) {
284 return $serialize_value->($self, $prop_def->{css}, $value);
285 } else {
286 return '';
287 }
288 };
289 } elsif ($prop_def->{serialize_shorthand} or
290 $prop_def->{serialize_multiple}) {
291 *{ $method_name } = sub {
292 ## TODO: setter
293 my $self = shift;
294
295 my $v = ($prop_def->{serialize_shorthand} or
296 $prop_def->{serialize_multiple})->($self);
297 if (defined $v->{$prop_def->{css}}) {
298 return $v->{$prop_def->{css}}->[0];
299 } else {
300 return '';
301 }
302 };
303 } else {
304 ## TODO: This should be an error of the implementation.
305 ## However, currently some shorthand properties does not have
306 ## serializer.
307 ## TODO: Remove {serialize} from shorthand properties, since
308 ## they have no effect.
309 warn "$0: No computed value function for $method_name";
310 #die "$0: No computed value function for $method_name";
311 *{ $method_name } = sub { };
312 }
313 goto &{ $AUTOLOAD };
314 } else {
315 require Carp;
316 Carp::croak (qq<Can't locate method "$AUTOLOAD">);
317 }
318 } # AUTOLOAD
319
320 use overload
321 '@{}' => sub {
322 tie my @list, ref $_[0], $_[0];
323 return \@list;
324 },
325 fallback => 1;
326
327 sub TIEARRAY ($$) { $_[1] }
328
329 ## |CSSStyleDeclaration| attributes
330
331 sub css_text ($;$) {
332 ## TODO: error if modified
333
334 my $self = shift;
335 require Whatpm::CSS::Parser;
336
337 ## NOTE: Where and how white space characters are inserted are
338 ## intentionally changed from those in browsers so that properties are
339 ## more prettily printed.
340 ## See <http://suika.fam.cx/gate/2005/sw/cssText> for what browsers do.
341 ## TODO: ordering
342 ## TODO: any spec?
343 my $r = '';
344 my %serialized;
345 for my $prop_def (sort {$a->{css} cmp $b->{css}}
346 grep {$_->{compute} or
347 $_->{compute_multiple} or
348 $_->{serialize_multiple}}
349 values %$Whatpm::CSS::Parser::Prop) {
350 if ($prop_def->{serialize_multiple}) {
351 unless ($serialized{$prop_def->{serialize_multiple}}) {
352 $serialized{$prop_def->{serialize_multiple}} = 1;
353 my $v = $prop_def->{serialize_multiple}->($self);
354 for my $prop_name (sort {$a cmp $b} keys %$v) {
355 $r .= ' ' . $prop_name . ': ' . $v->{$prop_name}->[0];
356 $r .= ' ! ' . $v->{$prop_name}->[1] if length $v->{$prop_name}->[1];
357 $r .= ";\n";
358 }
359 }
360 } else {
361 my $prop_value = $$self->{cascade}->get_computed_value
362 ($$self->{element}, $prop_def->{css});
363 my $s = $serialize_value->($self, $prop_def->{css}, $prop_value);
364 if (length $s) {
365 $r .= ' ' . $prop_def->{css} . ': ' . $s;
366 $r .= ";\n";
367 } else {
368 ## NOTE: This should be an error of the implementation.
369 $r .= " /* $prop_def->{css}: ???; */\n";
370 }
371 }
372 }
373
374 ## ISSUE: Should we include CSS properties that are not supported?
375
376 return $r;
377 } # css_text
378
379 ## TODO: What should we enumerate is unclear.
380 sub length ($) {
381 require Whatpm::CSS::Parser;
382 return scalar @{[grep {$_}
383 values %$Whatpm::CSS::Parser::Key]};
384 } # length
385 *FETCHSIZE = \&length;
386
387 ## TODO: STORESIZE
388
389 ## |CSSStyleDeclaration| methods
390
391 sub get_property_priority ($$) { '' }
392
393 sub item ($$) {
394 require Whatpm::CSS::Parser;
395 return '' if $_[1] < 0;
396 ## TODO: ordering (should be same as that in |css_text|.
397 my $v = [sort {$a cmp $b}
398 map {$_->{css}}
399 grep {$_}
400 values %$Whatpm::CSS::Parser::Key]->[$_[1]];
401 return defined $v ? $v : '';
402 } # item
403 *FETCH = \&item;
404
405 ## TODO: STORE, DELETE
406
407 sub EXISTS ($$) {
408 return length $_[0]->item;
409 } # EXISTS
410
411 ## TODO: members
412
413 package Message::IF::CSSStyleDeclaration;
414 package Message::IF::CSS2Properties;
415
416 1;
417 ## $Date: 2008/01/26 05:12:05 $

admin@suikawiki.org
ViewVC Help
Powered by ViewVC 1.1.24