/[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 - (hide 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 wakaba 1.1 package Message::DOM::CSSStyleDeclaration;
2     use strict;
3 wakaba 1.15 our $VERSION=do{my @r=(q$Revision: 1.14 $=~/\d+/g);sprintf "%d."."%02d" x $#r,@r};
4 wakaba 1.11 push our @ISA, 'Message::IF::CSSStyleDeclaration',
5     'Message::IF::CSS2Properties';
6 wakaba 1.1
7 wakaba 1.15 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 wakaba 1.1 sub ____new ($) {
95     return bless \{}, $_[0];
96     } # ____new
97    
98 wakaba 1.3 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 wakaba 1.15 if (defined $prop_def->{key}) {
109 wakaba 1.13 *{ $method_name } = sub {
110     ## TODO: setter
111    
112     my $self = $_[0];
113     my $value = $$self->{$prop_def->{key}};
114     if ($value) {
115 wakaba 1.15 return $serialize_value->($self, $prop_def->{css}, $value->[0]);
116 wakaba 1.13 } 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 wakaba 1.3 goto &{ $AUTOLOAD };
139     } else {
140     require Carp;
141     Carp::croak (qq<Can't locate method "$AUTOLOAD">);
142     }
143     } # AUTOLOAD
144    
145 wakaba 1.11 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 wakaba 1.1 ## |CSSStyleDeclaration| attributes
155    
156 wakaba 1.2 sub css_text ($;$) {
157 wakaba 1.3 ## TODO: setter
158    
159 wakaba 1.9 ## 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 wakaba 1.3 require Whatpm::CSS::Parser;
165     my $self = $_[0];
166     my $r = '';
167 wakaba 1.7 my %serialized;
168 wakaba 1.13 for (sort {$a cmp $b} grep {$$self->{$_}} keys %$$self) {
169 wakaba 1.3 my $prop_def = $Whatpm::CSS::Parser::Key->{$_};
170     next unless $prop_def;
171 wakaba 1.7
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 wakaba 1.14 $r .= ' ' . $prop_name . ': ' . $v->{$prop_name}->[0];
178     $r .= ' ! ' . $v->{$prop_name}->[1] if length $v->{$prop_name}->[1];
179     $r .= ";\n";
180 wakaba 1.7 }
181     }
182     } else {
183     my $value = $$self->{$_};
184 wakaba 1.15 my $s = $serialize_value->($self, $prop_def->{css}, $value->[0]);
185 wakaba 1.10 if (length $s) {
186 wakaba 1.7 $r .= ' ' . $prop_def->{css} . ': ' . $s;
187 wakaba 1.10 $r .= ' ! ' . $value->[1] if length $value->[1];
188 wakaba 1.7 $r .= ";\n";
189     }
190 wakaba 1.3 }
191     }
192     return $r;
193 wakaba 1.2 } # css_text
194    
195 wakaba 1.11 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 wakaba 1.1 sub parent_rule ($) {
206     return ${$_[0]}->{parent_rule};
207     } # parent_rule
208    
209 wakaba 1.7 ## |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 wakaba 1.15 if (defined $prop_def->{key}) {
219 wakaba 1.14 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 wakaba 1.7 } # get_property_priority
234    
235 wakaba 1.11 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 wakaba 1.1 ## TODO: Implement other methods and attributes
254    
255 wakaba 1.4 package Message::DOM::CSSComputedStyleDeclaration;
256 wakaba 1.11 push our @ISA, 'Message::IF::CSSStyleDeclaration',
257     'Message::IF::CSS2Properties';
258 wakaba 1.4
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 wakaba 1.7 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 wakaba 1.13 if ($prop_def->{compute} or $prop_def->{compute_multiple}) {
277     *{ $method_name } = sub {
278     ## TODO: setter
279    
280     my $self = $_[0];
281 wakaba 1.12 my $value = $$self->{cascade}->get_computed_value
282     ($$self->{element}, $prop_def->{css});
283     if ($value) {
284 wakaba 1.15 return $serialize_value->($self, $prop_def->{css}, $value);
285 wakaba 1.12 } else {
286     return '';
287     }
288 wakaba 1.13 };
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 wakaba 1.12 if (defined $v->{$prop_def->{css}}) {
298 wakaba 1.13 return $v->{$prop_def->{css}}->[0];
299 wakaba 1.12 } else {
300     return '';
301     }
302 wakaba 1.13 };
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 wakaba 1.7 goto &{ $AUTOLOAD };
314     } else {
315     require Carp;
316     Carp::croak (qq<Can't locate method "$AUTOLOAD">);
317     }
318     } # AUTOLOAD
319    
320 wakaba 1.11 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 wakaba 1.4 sub css_text ($;$) {
332     ## TODO: error if modified
333    
334     my $self = shift;
335     require Whatpm::CSS::Parser;
336    
337 wakaba 1.9 ## 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 wakaba 1.4 ## TODO: ordering
342     ## TODO: any spec?
343     my $r = '';
344 wakaba 1.7 my %serialized;
345 wakaba 1.6 for my $prop_def (sort {$a->{css} cmp $b->{css}}
346 wakaba 1.7 grep {$_->{compute} or
347     $_->{compute_multiple} or
348     $_->{serialize_multiple}}
349 wakaba 1.6 values %$Whatpm::CSS::Parser::Prop) {
350 wakaba 1.7 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 wakaba 1.14 $r .= ' ' . $prop_name . ': ' . $v->{$prop_name}->[0];
356     $r .= ' ! ' . $v->{$prop_name}->[1] if length $v->{$prop_name}->[1];
357     $r .= ";\n";
358 wakaba 1.7 }
359     }
360 wakaba 1.5 } else {
361 wakaba 1.7 my $prop_value = $$self->{cascade}->get_computed_value
362     ($$self->{element}, $prop_def->{css});
363 wakaba 1.15 my $s = $serialize_value->($self, $prop_def->{css}, $prop_value);
364 wakaba 1.10 if (length $s) {
365 wakaba 1.7 $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 wakaba 1.4 }
372     }
373 wakaba 1.6
374     ## ISSUE: Should we include CSS properties that are not supported?
375    
376 wakaba 1.4 return $r;
377     } # css_text
378    
379 wakaba 1.11 ## 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 wakaba 1.7 ## |CSSStyleDeclaration| methods
390    
391 wakaba 1.10 sub get_property_priority ($$) { '' }
392 wakaba 1.7
393 wakaba 1.11 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 wakaba 1.4 ## TODO: members
412    
413 wakaba 1.1 package Message::IF::CSSStyleDeclaration;
414 wakaba 1.11 package Message::IF::CSS2Properties;
415 wakaba 1.1
416     1;
417 wakaba 1.15 ## $Date: 2008/01/26 05:12:05 $

admin@suikawiki.org
ViewVC Help
Powered by ViewVC 1.1.24