line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package CSS::Orientation; |
2
|
|
|
|
|
|
|
|
3
|
12
|
|
|
12
|
|
297194
|
use strict; |
|
12
|
|
|
|
|
29
|
|
|
12
|
|
|
|
|
457
|
|
4
|
12
|
|
|
12
|
|
58
|
use warnings; |
|
12
|
|
|
|
|
22
|
|
|
12
|
|
|
|
|
592
|
|
5
|
|
|
|
|
|
|
|
6
|
|
|
|
|
|
|
our $VERSION = '0.01'; |
7
|
|
|
|
|
|
|
|
8
|
12
|
|
|
12
|
|
64
|
use base qw( Exporter ); |
|
12
|
|
|
|
|
29
|
|
|
12
|
|
|
|
|
66591
|
|
9
|
|
|
|
|
|
|
|
10
|
|
|
|
|
|
|
our %EXPORT_TAGS = ( 'all' => [ qw( |
11
|
|
|
|
|
|
|
ChangeLeftToRightToLeft |
12
|
|
|
|
|
|
|
) ] ); |
13
|
|
|
|
|
|
|
|
14
|
|
|
|
|
|
|
our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } ); |
15
|
|
|
|
|
|
|
|
16
|
|
|
|
|
|
|
# h [0-9a-f] ; a hexadecimal digit |
17
|
|
|
|
|
|
|
our $HEX = q'[0-9a-f]'; |
18
|
|
|
|
|
|
|
|
19
|
|
|
|
|
|
|
# nonascii [\200-\377] |
20
|
|
|
|
|
|
|
our $NON_ASCII = q'[\200-\377]'; |
21
|
|
|
|
|
|
|
|
22
|
|
|
|
|
|
|
# unicode \\{h}{1,6}(\r\n|[ \t\r\n\f])? |
23
|
|
|
|
|
|
|
our $UNICODE = q'(?:(?:\\' . $HEX . q'{1,6})(?:\r\n|[ \t\r\n\f])?)'; |
24
|
|
|
|
|
|
|
|
25
|
|
|
|
|
|
|
# escape {unicode}|\\[^\r\n\f0-9a-f] |
26
|
|
|
|
|
|
|
our $ESCAPE = q'(?:' . $UNICODE . q'|\\[^\r\n\f0-9a-f])'; |
27
|
|
|
|
|
|
|
|
28
|
|
|
|
|
|
|
# nmstart [_a-z]|{nonascii}|{escape} |
29
|
|
|
|
|
|
|
our $NMSTART = q'(?:[_a-z]|' . $NON_ASCII . q'|' . $ESCAPE . q')'; |
30
|
|
|
|
|
|
|
|
31
|
|
|
|
|
|
|
# nmchar [_a-z0-9-]|{nonascii}|{escape} |
32
|
|
|
|
|
|
|
our $NMCHAR = q'(?:[_a-z0-9-]|' . $NON_ASCII . q'|' . $ESCAPE . q')'; |
33
|
|
|
|
|
|
|
|
34
|
|
|
|
|
|
|
# ident -?{nmstart}{nmchar}* |
35
|
|
|
|
|
|
|
our $IDENT = q'-?' . $NMSTART . $NMCHAR . '*'; |
36
|
|
|
|
|
|
|
|
37
|
|
|
|
|
|
|
# name {nmchar}+ |
38
|
|
|
|
|
|
|
our $NAME = $NMCHAR . q'+'; |
39
|
|
|
|
|
|
|
|
40
|
|
|
|
|
|
|
# hash |
41
|
|
|
|
|
|
|
our $HASH = q'#' . $NAME; |
42
|
|
|
|
|
|
|
|
43
|
|
|
|
|
|
|
# num [0-9]+|[0-9]*"."[0-9]+ |
44
|
|
|
|
|
|
|
our $NUM = q'(?:[0-9]*\.[0-9]+|[0-9]+)'; |
45
|
|
|
|
|
|
|
|
46
|
|
|
|
|
|
|
# s [ \t\r\n\f] |
47
|
|
|
|
|
|
|
our $SPACE = q'[ \t\r\n\f]'; |
48
|
|
|
|
|
|
|
|
49
|
|
|
|
|
|
|
# w {s}* |
50
|
|
|
|
|
|
|
our $WHITESPACE = '(?:' . $SPACE . q'*)'; |
51
|
|
|
|
|
|
|
|
52
|
|
|
|
|
|
|
# url special chars |
53
|
|
|
|
|
|
|
our $URL_SPECIAL_CHARS = q'[!#$%&*-~]'; |
54
|
|
|
|
|
|
|
|
55
|
|
|
|
|
|
|
# url chars ({url_special_chars}|{nonascii}|{escape})* |
56
|
|
|
|
|
|
|
our $URL_CHARS = sprintf( q'(?:%s|%s|%s)*', $URL_SPECIAL_CHARS, $NON_ASCII, $ESCAPE ); |
57
|
|
|
|
|
|
|
|
58
|
|
|
|
|
|
|
# comments |
59
|
|
|
|
|
|
|
# see http://www.w3.org/TR/CSS21/grammar.html |
60
|
|
|
|
|
|
|
our $COMMENT = q'/\*[^*]*\*+([^/*][^*]*\*+)*/'; |
61
|
|
|
|
|
|
|
|
62
|
|
|
|
|
|
|
# {E}{M} {return EMS;} |
63
|
|
|
|
|
|
|
# {E}{X} {return EXS;} |
64
|
|
|
|
|
|
|
# {P}{X} {return LENGTH;} |
65
|
|
|
|
|
|
|
# {C}{M} {return LENGTH;} |
66
|
|
|
|
|
|
|
# {M}{M} {return LENGTH;} |
67
|
|
|
|
|
|
|
# {I}{N} {return LENGTH;} |
68
|
|
|
|
|
|
|
# {P}{T} {return LENGTH;} |
69
|
|
|
|
|
|
|
# {P}{C} {return LENGTH;} |
70
|
|
|
|
|
|
|
# {D}{E}{G} {return ANGLE;} |
71
|
|
|
|
|
|
|
# {R}{A}{D} {return ANGLE;} |
72
|
|
|
|
|
|
|
# {G}{R}{A}{D} {return ANGLE;} |
73
|
|
|
|
|
|
|
# {M}{S} {return TIME;} |
74
|
|
|
|
|
|
|
# {S} {return TIME;} |
75
|
|
|
|
|
|
|
# {H}{Z} {return FREQ;} |
76
|
|
|
|
|
|
|
# {K}{H}{Z} {return FREQ;} |
77
|
|
|
|
|
|
|
# % {return PERCENTAGE;} |
78
|
|
|
|
|
|
|
our $UNIT = q'(?:em|ex|px|cm|mm|in|pt|pc|deg|rad|grad|ms|s|hz|khz|%)'; |
79
|
|
|
|
|
|
|
|
80
|
|
|
|
|
|
|
# {num}{UNIT|IDENT} {return NUMBER;} |
81
|
|
|
|
|
|
|
our $QUANTITY = sprintf( '%s(?:%s%s|%s)?', $NUM, $WHITESPACE, $UNIT, $IDENT ); |
82
|
|
|
|
|
|
|
|
83
|
|
|
|
|
|
|
|
84
|
|
|
|
|
|
|
|
85
|
|
|
|
|
|
|
|
86
|
|
|
|
|
|
|
# Generic token delimiter character. |
87
|
|
|
|
|
|
|
our $TOKEN_DELIMITER = '~'; |
88
|
|
|
|
|
|
|
|
89
|
|
|
|
|
|
|
# This is a temporary match token we use when swapping strings. |
90
|
|
|
|
|
|
|
our $TMP_TOKEN = sprintf( '%sTMP%s', $TOKEN_DELIMITER, $TOKEN_DELIMITER ); |
91
|
|
|
|
|
|
|
|
92
|
|
|
|
|
|
|
# Token to be used for joining lines. |
93
|
|
|
|
|
|
|
our $TOKEN_LINES = sprintf( '%sJ%s', $TOKEN_DELIMITER, $TOKEN_DELIMITER ); |
94
|
|
|
|
|
|
|
|
95
|
|
|
|
|
|
|
# Global constant text strings for CSS value matches. |
96
|
|
|
|
|
|
|
our $LTR = 'ltr'; |
97
|
|
|
|
|
|
|
our $RTL = 'rtl'; |
98
|
|
|
|
|
|
|
our $LEFT = 'left'; |
99
|
|
|
|
|
|
|
our $RIGHT = 'right'; |
100
|
|
|
|
|
|
|
|
101
|
|
|
|
|
|
|
# This is a lookbehind match to ensure that we don't replace instances |
102
|
|
|
|
|
|
|
# of our string token (left, rtl, etc...) if there's a letter in front of it. |
103
|
|
|
|
|
|
|
# Specifically, this prevents replacements like 'background: url(bright.png)'. |
104
|
|
|
|
|
|
|
our $LOOKBEHIND_NOT_LETTER = q'(?
|
105
|
|
|
|
|
|
|
|
106
|
|
|
|
|
|
|
# This is a lookahead match to make sure we don't replace left and right |
107
|
|
|
|
|
|
|
# in actual classnames, so that we don't break the HTML/CSS dependencies. |
108
|
|
|
|
|
|
|
# Read literally, it says ignore cases where the word left, for instance, is |
109
|
|
|
|
|
|
|
# directly followed by valid classname characters and a curly brace. |
110
|
|
|
|
|
|
|
# ex: .column-left {float: left} will become .column-left {float: right} |
111
|
|
|
|
|
|
|
our $LOOKAHEAD_NOT_OPEN_BRACE = sprintf( q'(?!(?:%s|%s|%s|#|\:|\.|\,|\+|>)*?{)', |
112
|
|
|
|
|
|
|
$NMCHAR, $TOKEN_LINES, $SPACE ); |
113
|
|
|
|
|
|
|
|
114
|
|
|
|
|
|
|
# These two lookaheads are to test whether or not we are within a |
115
|
|
|
|
|
|
|
# background: url(HERE) situation. |
116
|
|
|
|
|
|
|
# Ref: http://www.w3.org/TR/CSS21/syndata.html#uri |
117
|
|
|
|
|
|
|
our $VALID_AFTER_URI_CHARS = sprintf( q'[\'\"]?%s', $WHITESPACE ); |
118
|
|
|
|
|
|
|
our $LOOKAHEAD_NOT_CLOSING_PAREN = sprintf( q'(?!%s?%s\))', $URL_CHARS, |
119
|
|
|
|
|
|
|
$VALID_AFTER_URI_CHARS ); |
120
|
|
|
|
|
|
|
our $LOOKAHEAD_FOR_CLOSING_PAREN = sprintf( q'(?=%s?%s\))', $URL_CHARS, |
121
|
|
|
|
|
|
|
$VALID_AFTER_URI_CHARS ); |
122
|
|
|
|
|
|
|
|
123
|
|
|
|
|
|
|
# Compile a regex to swap left and right values in 4 part notations. |
124
|
|
|
|
|
|
|
# We need to match negatives and decimal numeric values. |
125
|
|
|
|
|
|
|
# The case of border-radius is extra complex, so we handle it separately below. |
126
|
|
|
|
|
|
|
# ex. 'margin: .25em -2px 3px 0' becomes 'margin: .25em 0 3px -2px'. |
127
|
|
|
|
|
|
|
|
128
|
|
|
|
|
|
|
our $POSSIBLY_NEGATIVE_QUANTITY = sprintf( q'((?:-?%s)|(?:inherit|auto))', $QUANTITY ); |
129
|
|
|
|
|
|
|
our $POSSIBLY_NEGATIVE_QUANTITY_SPACE = sprintf( q'%s%s%s', $POSSIBLY_NEGATIVE_QUANTITY, |
130
|
|
|
|
|
|
|
$SPACE, |
131
|
|
|
|
|
|
|
$WHITESPACE ); |
132
|
|
|
|
|
|
|
|
133
|
|
|
|
|
|
|
our $FOUR_NOTATION_QUANTITY_RE = risprintf( q'%s%s%s%s', |
134
|
|
|
|
|
|
|
$POSSIBLY_NEGATIVE_QUANTITY_SPACE, |
135
|
|
|
|
|
|
|
$POSSIBLY_NEGATIVE_QUANTITY_SPACE, |
136
|
|
|
|
|
|
|
$POSSIBLY_NEGATIVE_QUANTITY_SPACE, |
137
|
|
|
|
|
|
|
$POSSIBLY_NEGATIVE_QUANTITY ); |
138
|
|
|
|
|
|
|
our $COLOR = sprintf( q'(%s|%s)', $NAME, $HASH ); |
139
|
|
|
|
|
|
|
our $COLOR_SPACE = sprintf( q'%s%s', $COLOR, $SPACE ); |
140
|
|
|
|
|
|
|
our $FOUR_NOTATION_COLOR_RE = risprintf( q'(-color%s:%s)%s%s%s(%s)', |
141
|
|
|
|
|
|
|
$WHITESPACE, |
142
|
|
|
|
|
|
|
$WHITESPACE, |
143
|
|
|
|
|
|
|
$COLOR_SPACE, |
144
|
|
|
|
|
|
|
$COLOR_SPACE, |
145
|
|
|
|
|
|
|
$COLOR_SPACE, |
146
|
|
|
|
|
|
|
$COLOR ); |
147
|
|
|
|
|
|
|
|
148
|
|
|
|
|
|
|
# border-radius is very different from usual 4 part notation: ABCD should |
149
|
|
|
|
|
|
|
# change to BADC (while it would be ADCB in normal 4 part notation), ABC |
150
|
|
|
|
|
|
|
# should change to BABC, and AB should change to BA |
151
|
|
|
|
|
|
|
our $BORDER_RADIUS_RE = risprintf( q'((?:%s)?)border-radius(%s:%s)' . |
152
|
|
|
|
|
|
|
'(?:%s)?(?:%s)?(?:%s)?(?:%s)' . |
153
|
|
|
|
|
|
|
'(?:%s/%s(?:%s)?(?:%s)?(?:%s)?(?:%s))?', $IDENT, |
154
|
|
|
|
|
|
|
$WHITESPACE, |
155
|
|
|
|
|
|
|
$WHITESPACE, |
156
|
|
|
|
|
|
|
$POSSIBLY_NEGATIVE_QUANTITY_SPACE, |
157
|
|
|
|
|
|
|
$POSSIBLY_NEGATIVE_QUANTITY_SPACE, |
158
|
|
|
|
|
|
|
$POSSIBLY_NEGATIVE_QUANTITY_SPACE, |
159
|
|
|
|
|
|
|
$POSSIBLY_NEGATIVE_QUANTITY, |
160
|
|
|
|
|
|
|
$WHITESPACE, |
161
|
|
|
|
|
|
|
$WHITESPACE, |
162
|
|
|
|
|
|
|
$POSSIBLY_NEGATIVE_QUANTITY_SPACE, |
163
|
|
|
|
|
|
|
$POSSIBLY_NEGATIVE_QUANTITY_SPACE, |
164
|
|
|
|
|
|
|
$POSSIBLY_NEGATIVE_QUANTITY_SPACE, |
165
|
|
|
|
|
|
|
$POSSIBLY_NEGATIVE_QUANTITY ); |
166
|
|
|
|
|
|
|
|
167
|
|
|
|
|
|
|
|
168
|
|
|
|
|
|
|
|
169
|
|
|
|
|
|
|
# Compile the cursor resize regexes |
170
|
|
|
|
|
|
|
our $CURSOR_EAST_RE = resprintf( $LOOKBEHIND_NOT_LETTER . '([ns]?)e-resize' ); |
171
|
|
|
|
|
|
|
our $CURSOR_WEST_RE = resprintf( $LOOKBEHIND_NOT_LETTER . '([ns]?)w-resize' ); |
172
|
|
|
|
|
|
|
|
173
|
|
|
|
|
|
|
# Matches the condition where we need to replace the horizontal component |
174
|
|
|
|
|
|
|
# of a background-position value when expressed in horizontal percentage. |
175
|
|
|
|
|
|
|
# Had to make two regexes because in the case of position-x there is only |
176
|
|
|
|
|
|
|
# one quantity, and otherwise we don't want to match and change cases with only |
177
|
|
|
|
|
|
|
# one quantity. |
178
|
|
|
|
|
|
|
our $BG_HORIZONTAL_PERCENTAGE_RE = resprintf( q'background(-position)?(%s:%s)' . |
179
|
|
|
|
|
|
|
q'([^%%]*?)(%s)%%' . |
180
|
|
|
|
|
|
|
q'(%s(?:%s|top|center|bottom))', $WHITESPACE, |
181
|
|
|
|
|
|
|
$WHITESPACE, |
182
|
|
|
|
|
|
|
$NUM, |
183
|
|
|
|
|
|
|
$WHITESPACE, |
184
|
|
|
|
|
|
|
$POSSIBLY_NEGATIVE_QUANTITY ); |
185
|
|
|
|
|
|
|
|
186
|
|
|
|
|
|
|
our $BG_HORIZONTAL_PERCENTAGE_X_RE = resprintf( q'background-position-x(%s:%s)' . |
187
|
|
|
|
|
|
|
q'(%s)%%', $WHITESPACE, |
188
|
|
|
|
|
|
|
$WHITESPACE, |
189
|
|
|
|
|
|
|
$NUM ); |
190
|
|
|
|
|
|
|
# Non-percentage units used for CSS lengths |
191
|
|
|
|
|
|
|
our $LENGTH_UNIT = q'(?:em|ex|px|cm|mm|in|pt|pc)'; |
192
|
|
|
|
|
|
|
# To make sure the lone 0 is not just starting a number (like "02") or a percentage like ("0 %") |
193
|
|
|
|
|
|
|
our $LOOKAHEAD_END_OF_ZERO = sprintf( '(?![0-9]|%s%%)', $WHITESPACE ); |
194
|
|
|
|
|
|
|
# A length with a unit specified. Matches "0" too, as it's a length, not a percentage. |
195
|
|
|
|
|
|
|
our $LENGTH = sprintf( '(?:-?%s(?:%s%s)|0+%s)', $NUM, |
196
|
|
|
|
|
|
|
$WHITESPACE, |
197
|
|
|
|
|
|
|
$LENGTH_UNIT, |
198
|
|
|
|
|
|
|
$LOOKAHEAD_END_OF_ZERO ); |
199
|
|
|
|
|
|
|
|
200
|
|
|
|
|
|
|
# Zero length. Used in the replacement functions. |
201
|
|
|
|
|
|
|
our $ZERO_LENGTH = resprintf( q'(?:-?0+(?:%s%s)|0+%s)$', $WHITESPACE, |
202
|
|
|
|
|
|
|
$LENGTH_UNIT, |
203
|
|
|
|
|
|
|
$LOOKAHEAD_END_OF_ZERO ); |
204
|
|
|
|
|
|
|
|
205
|
|
|
|
|
|
|
# Matches background, background-position, and background-position-x |
206
|
|
|
|
|
|
|
# properties when using a CSS length for its horizontal positioning. |
207
|
|
|
|
|
|
|
our $BG_HORIZONTAL_LENGTH_RE = resprintf( q'background(-position)?(%s:%s)' . |
208
|
|
|
|
|
|
|
q'((?:.+?%s+)??)(%s)' . |
209
|
|
|
|
|
|
|
q'((?:%s+)(?:%s|top|center|bottom))', $WHITESPACE, |
210
|
|
|
|
|
|
|
$WHITESPACE, |
211
|
|
|
|
|
|
|
$SPACE, |
212
|
|
|
|
|
|
|
$LENGTH, |
213
|
|
|
|
|
|
|
$SPACE, |
214
|
|
|
|
|
|
|
$POSSIBLY_NEGATIVE_QUANTITY ); |
215
|
|
|
|
|
|
|
|
216
|
|
|
|
|
|
|
our $BG_HORIZONTAL_LENGTH_X_RE = resprintf( q'background-position-x(%s:%s)' . |
217
|
|
|
|
|
|
|
q'(%s)', $WHITESPACE, |
218
|
|
|
|
|
|
|
$WHITESPACE, |
219
|
|
|
|
|
|
|
$LENGTH ); |
220
|
|
|
|
|
|
|
|
221
|
|
|
|
|
|
|
# Matches the opening of a body selector. |
222
|
|
|
|
|
|
|
our $BODY_SELECTOR = sprintf( q'body%s{%s', $WHITESPACE, $WHITESPACE ); |
223
|
|
|
|
|
|
|
|
224
|
|
|
|
|
|
|
# Matches anything up until the closing of a selector. |
225
|
|
|
|
|
|
|
our $CHARS_WITHIN_SELECTOR = q'[^\}]*?'; |
226
|
|
|
|
|
|
|
|
227
|
|
|
|
|
|
|
# Matches the direction property in a selector. |
228
|
|
|
|
|
|
|
our $DIRECTION_RE = sprintf( q'direction%s:%s', $WHITESPACE, $WHITESPACE ); |
229
|
|
|
|
|
|
|
|
230
|
|
|
|
|
|
|
|
231
|
|
|
|
|
|
|
|
232
|
|
|
|
|
|
|
sub resprintf { |
233
|
120
|
|
|
120
|
0
|
182
|
my $fmt = shift; |
234
|
120
|
|
|
|
|
345
|
my $ret = sprintf( $fmt, @_ ); |
235
|
|
|
|
|
|
|
|
236
|
120
|
|
|
|
|
6513
|
return qr/$ret/; |
237
|
|
|
|
|
|
|
} |
238
|
|
|
|
|
|
|
|
239
|
|
|
|
|
|
|
sub risprintf { |
240
|
180
|
|
|
180
|
0
|
261
|
my $fmt = shift; |
241
|
180
|
|
|
|
|
712
|
my $ret = sprintf( $fmt, @_ ); |
242
|
|
|
|
|
|
|
|
243
|
180
|
|
|
|
|
61699
|
return qr/$ret/i; |
244
|
|
|
|
|
|
|
} |
245
|
|
|
|
|
|
|
|
246
|
|
|
|
|
|
|
# These allow us to swap "ltr" with "rtl" and vice versa ONLY within the |
247
|
|
|
|
|
|
|
# body selector and on the same line. |
248
|
|
|
|
|
|
|
our $BODY_DIRECTION_LTR_RE = risprintf( q'(%s)(%s)(%s)(ltr)', |
249
|
|
|
|
|
|
|
$BODY_SELECTOR, $CHARS_WITHIN_SELECTOR, |
250
|
|
|
|
|
|
|
$DIRECTION_RE ); |
251
|
|
|
|
|
|
|
our $BODY_DIRECTION_RTL_RE = risprintf( q'(%s)(%s)(%s)(rtl)', |
252
|
|
|
|
|
|
|
$BODY_SELECTOR, $CHARS_WITHIN_SELECTOR, |
253
|
|
|
|
|
|
|
$DIRECTION_RE ); |
254
|
|
|
|
|
|
|
|
255
|
|
|
|
|
|
|
# Allows us to swap "direction:ltr" with "direction:rtl" and |
256
|
|
|
|
|
|
|
# vice versa anywhere in a line. |
257
|
|
|
|
|
|
|
our $DIRECTION_LTR_RE = resprintf( q'%s(ltr)', $DIRECTION_RE ); |
258
|
|
|
|
|
|
|
our $DIRECTION_RTL_RE = resprintf( q'%s(rtl)', $DIRECTION_RE ); |
259
|
|
|
|
|
|
|
|
260
|
|
|
|
|
|
|
# We want to be able to switch left with right and vice versa anywhere |
261
|
|
|
|
|
|
|
# we encounter left/right strings, EXCEPT inside the background:url(). The next |
262
|
|
|
|
|
|
|
# two regexes are for that purpose. We have alternate IN_URL versions of the |
263
|
|
|
|
|
|
|
# regexes compiled in case the user passes the flag that they do |
264
|
|
|
|
|
|
|
# actually want to have left and right swapped inside of background:urls. |
265
|
|
|
|
|
|
|
our $LEFT_RE = risprintf( '%s((?:top|bottom)?)(%s)%s%s', $LOOKBEHIND_NOT_LETTER, |
266
|
|
|
|
|
|
|
$LEFT, |
267
|
|
|
|
|
|
|
$LOOKAHEAD_NOT_CLOSING_PAREN, |
268
|
|
|
|
|
|
|
$LOOKAHEAD_NOT_OPEN_BRACE ); |
269
|
|
|
|
|
|
|
our $RIGHT_RE = risprintf( '%s((?:top|bottom)?)(%s)%s%s', $LOOKBEHIND_NOT_LETTER, |
270
|
|
|
|
|
|
|
$RIGHT, |
271
|
|
|
|
|
|
|
$LOOKAHEAD_NOT_CLOSING_PAREN, |
272
|
|
|
|
|
|
|
$LOOKAHEAD_NOT_OPEN_BRACE ); |
273
|
|
|
|
|
|
|
our $LEFT_IN_URL_RE = risprintf( '%s(%s)%s', $LOOKBEHIND_NOT_LETTER, |
274
|
|
|
|
|
|
|
$LEFT, |
275
|
|
|
|
|
|
|
$LOOKAHEAD_FOR_CLOSING_PAREN ); |
276
|
|
|
|
|
|
|
our $RIGHT_IN_URL_RE = risprintf( '%s(%s)%s', $LOOKBEHIND_NOT_LETTER, |
277
|
|
|
|
|
|
|
$RIGHT, |
278
|
|
|
|
|
|
|
$LOOKAHEAD_FOR_CLOSING_PAREN ); |
279
|
|
|
|
|
|
|
our $LTR_IN_URL_RE = risprintf( '%s(%s)%s', $LOOKBEHIND_NOT_LETTER, |
280
|
|
|
|
|
|
|
$LTR, |
281
|
|
|
|
|
|
|
$LOOKAHEAD_FOR_CLOSING_PAREN ); |
282
|
|
|
|
|
|
|
our $RTL_IN_URL_RE = risprintf( '%s(%s)%s', $LOOKBEHIND_NOT_LETTER, |
283
|
|
|
|
|
|
|
$RTL, |
284
|
|
|
|
|
|
|
$LOOKAHEAD_FOR_CLOSING_PAREN ); |
285
|
|
|
|
|
|
|
|
286
|
|
|
|
|
|
|
our $COMMENT_RE = risprintf( '(%s)', $COMMENT ); |
287
|
|
|
|
|
|
|
|
288
|
|
|
|
|
|
|
our $NOFLIP_TOKEN = q'@noflip'; |
289
|
|
|
|
|
|
|
# The NOFLIP_TOKEN inside of a comment. For now, this requires that comments |
290
|
|
|
|
|
|
|
# be in the input, which means users of a css compiler would have to run |
291
|
|
|
|
|
|
|
# this script first if they want this functionality. |
292
|
|
|
|
|
|
|
our $NOFLIP_ANNOTATION = resprintf( q'/\*!?%s%s%s\*/', $WHITESPACE, |
293
|
|
|
|
|
|
|
$NOFLIP_TOKEN, |
294
|
|
|
|
|
|
|
$WHITESPACE ); |
295
|
|
|
|
|
|
|
|
296
|
|
|
|
|
|
|
# After a NOFLIP_ANNOTATION, and within a class selector, we want to be able |
297
|
|
|
|
|
|
|
# to set aside a single rule not to be flipped. We can do this by matching |
298
|
|
|
|
|
|
|
# our NOFLIP annotation and then using a lookahead to make sure there is not |
299
|
|
|
|
|
|
|
# an opening brace before the match. |
300
|
|
|
|
|
|
|
our $NOFLIP_SINGLE_RE = risprintf( q'(%s%s[^;}]+;?)', $NOFLIP_ANNOTATION, |
301
|
|
|
|
|
|
|
$LOOKAHEAD_NOT_OPEN_BRACE ); |
302
|
|
|
|
|
|
|
|
303
|
|
|
|
|
|
|
# After a NOFLIP_ANNOTATION, we want to grab anything up until the next } which |
304
|
|
|
|
|
|
|
# means the entire following class block. This will prevent all of its |
305
|
|
|
|
|
|
|
# declarations from being flipped. |
306
|
|
|
|
|
|
|
our $NOFLIP_CLASS_RE = risprintf( q'(%s%s})', $NOFLIP_ANNOTATION, |
307
|
|
|
|
|
|
|
$CHARS_WITHIN_SELECTOR ); |
308
|
|
|
|
|
|
|
|
309
|
|
|
|
|
|
|
# border-radis properties and their values |
310
|
|
|
|
|
|
|
our $BORDER_RADIUS_TOKENIZER_RE = risprintf( q'((?:%s)?border-radius%s:[^;}]+;?)', $IDENT, |
311
|
|
|
|
|
|
|
$WHITESPACE ); |
312
|
|
|
|
|
|
|
|
313
|
|
|
|
|
|
|
our $GRADIENT_RE = qr/ ( |
314
|
|
|
|
|
|
|
$CSS::Orientation::IDENT |
315
|
|
|
|
|
|
|
[\.-] gradient |
316
|
|
|
|
|
|
|
$CSS::Orientation::WHITESPACE |
317
|
|
|
|
|
|
|
\( (?: (?>[^()]+) | \([^()]*\) )+ \) |
318
|
|
|
|
|
|
|
) /ix; |
319
|
|
|
|
|
|
|
|
320
|
|
|
|
|
|
|
sub FixBodyDirectionLtrAndRtl { |
321
|
103
|
|
|
103
|
0
|
121
|
my ( $line ) = @_; |
322
|
|
|
|
|
|
|
|
323
|
103
|
|
|
|
|
323
|
$line =~ s!$BODY_DIRECTION_LTR_RE!$1$2$3$TMP_TOKEN!gms; |
324
|
103
|
|
|
|
|
292
|
$line =~ s!$BODY_DIRECTION_RTL_RE!$1$2$3$LTR!gms; |
325
|
103
|
|
|
|
|
209
|
$line =~ s!$TMP_TOKEN!$RTL!gms; |
326
|
|
|
|
|
|
|
|
327
|
103
|
|
|
|
|
174
|
return $line; |
328
|
|
|
|
|
|
|
} |
329
|
|
|
|
|
|
|
|
330
|
|
|
|
|
|
|
sub FixLeftAndRight { |
331
|
103
|
|
|
103
|
0
|
125
|
my ( $line ) = @_; |
332
|
|
|
|
|
|
|
|
333
|
103
|
|
|
|
|
1590
|
$line =~ s!$LEFT_RE!$1$TMP_TOKEN!gms; |
334
|
103
|
|
|
|
|
1781
|
$line =~ s!$RIGHT_RE!$1$LEFT!gms; |
335
|
103
|
|
|
|
|
302
|
$line =~ s!$TMP_TOKEN!$RIGHT!gms; |
336
|
|
|
|
|
|
|
|
337
|
103
|
|
|
|
|
275
|
return $line; |
338
|
|
|
|
|
|
|
} |
339
|
|
|
|
|
|
|
|
340
|
|
|
|
|
|
|
sub FixLeftAndRightInUrl { |
341
|
12
|
|
|
12
|
0
|
23
|
my ( $line ) = @_; |
342
|
|
|
|
|
|
|
|
343
|
12
|
|
|
|
|
80
|
$line =~ s!$LEFT_IN_URL_RE!$TMP_TOKEN!gms; |
344
|
12
|
|
|
|
|
63
|
$line =~ s!$RIGHT_IN_URL_RE!$LEFT!gms; |
345
|
12
|
|
|
|
|
45
|
$line =~ s!$TMP_TOKEN!$RIGHT!gms; |
346
|
|
|
|
|
|
|
|
347
|
12
|
|
|
|
|
35
|
return $line; |
348
|
|
|
|
|
|
|
} |
349
|
|
|
|
|
|
|
|
350
|
|
|
|
|
|
|
sub FixLtrAndRtlInUrl { |
351
|
12
|
|
|
12
|
0
|
26
|
my ( $line ) = @_; |
352
|
|
|
|
|
|
|
|
353
|
12
|
|
|
|
|
74
|
$line =~ s!$LTR_IN_URL_RE!$TMP_TOKEN!gms; |
354
|
12
|
|
|
|
|
75
|
$line =~ s!$RTL_IN_URL_RE!$LTR!gms; |
355
|
12
|
|
|
|
|
55
|
$line =~ s!$TMP_TOKEN!$RTL!gms; |
356
|
|
|
|
|
|
|
|
357
|
12
|
|
|
|
|
28
|
return $line; |
358
|
|
|
|
|
|
|
} |
359
|
|
|
|
|
|
|
|
360
|
|
|
|
|
|
|
sub FixCursorProperties { |
361
|
103
|
|
|
103
|
0
|
121
|
my ( $line ) = @_; |
362
|
|
|
|
|
|
|
|
363
|
103
|
|
|
|
|
396
|
$line =~ s!$CURSOR_EAST_RE!$1$TMP_TOKEN!gms; |
364
|
103
|
|
|
|
|
263
|
$line =~ s!$CURSOR_WEST_RE!${1}e-resize!gms; |
365
|
103
|
|
|
|
|
241
|
$line =~ s!$TMP_TOKEN!w-resize!gms; |
366
|
|
|
|
|
|
|
|
367
|
103
|
|
|
|
|
248
|
return $line; |
368
|
|
|
|
|
|
|
} |
369
|
|
|
|
|
|
|
|
370
|
|
|
|
|
|
|
sub FixBackgroundPosition { |
371
|
110
|
|
|
110
|
0
|
155
|
my ( $line, $ignore_bad_bgp ) = @_; |
372
|
|
|
|
|
|
|
|
373
|
|
|
|
|
|
|
# leave full match undef where not needed |
374
|
110
|
|
|
|
|
728
|
$line =~ s!$BG_HORIZONTAL_PERCENTAGE_RE!CalculateNewBackgroundPosition(undef,$1,$2,$3,$4,$5,$6)!egms; |
|
13
|
|
|
|
|
66
|
|
375
|
110
|
|
|
|
|
381
|
$line =~ s!$BG_HORIZONTAL_PERCENTAGE_X_RE!CalculateNewBackgroundPositionX(undef,$1,$2)!egms; |
|
2
|
|
|
|
|
9
|
|
376
|
|
|
|
|
|
|
|
377
|
110
|
|
|
|
|
7074
|
$line =~ s!($BG_HORIZONTAL_LENGTH_RE)! |
378
|
1
|
50
|
|
|
|
6
|
defined( $_ = CalculateNewBackgroundLengthPosition( $1, $2, $3, $4, $5, $6, $7, $ignore_bad_bgp ) ) |
379
|
|
|
|
|
|
|
? $_ |
380
|
|
|
|
|
|
|
: return undef |
381
|
|
|
|
|
|
|
!egmsx; |
382
|
|
|
|
|
|
|
|
383
|
110
|
|
|
|
|
447
|
$line =~ s!($BG_HORIZONTAL_LENGTH_X_RE)! |
384
|
1
|
50
|
|
|
|
6
|
defined( $_ = CalculateNewBackgroundLengthPositionX( $1, $2, $3, $ignore_bad_bgp ) ) |
385
|
|
|
|
|
|
|
? $_ |
386
|
|
|
|
|
|
|
: return undef |
387
|
|
|
|
|
|
|
!egmsx; |
388
|
|
|
|
|
|
|
|
389
|
110
|
|
|
|
|
314
|
return $line; |
390
|
|
|
|
|
|
|
} |
391
|
|
|
|
|
|
|
|
392
|
|
|
|
|
|
|
sub ReorderBorderRadiusPart { |
393
|
16
|
|
|
16
|
0
|
2096
|
my @part = grep defined, @_; |
394
|
|
|
|
|
|
|
|
395
|
16
|
100
|
|
|
|
63
|
if ( @part == 4 ) { |
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
396
|
4
|
|
|
|
|
25
|
return join( ' ', @part[ 1, 0, 3, 2 ] ); |
397
|
|
|
|
|
|
|
} |
398
|
|
|
|
|
|
|
elsif ( @part == 3 ) { |
399
|
4
|
|
|
|
|
20
|
return join( ' ', @part[ 1, 0, 1, 2 ] ); |
400
|
|
|
|
|
|
|
} |
401
|
|
|
|
|
|
|
elsif ( @part == 2 ) { |
402
|
2
|
|
|
|
|
10
|
return join( ' ', @part[ 1, 0, ] ); |
403
|
|
|
|
|
|
|
} |
404
|
|
|
|
|
|
|
elsif ( @part == 1 ) { |
405
|
2
|
|
|
|
|
7
|
return $part[ 0 ]; |
406
|
|
|
|
|
|
|
} |
407
|
|
|
|
|
|
|
else { |
408
|
4
|
|
|
|
|
9
|
return ''; |
409
|
|
|
|
|
|
|
} |
410
|
|
|
|
|
|
|
} |
411
|
|
|
|
|
|
|
|
412
|
|
|
|
|
|
|
sub ReorderBorderRadius { |
413
|
6
|
|
|
6
|
0
|
51
|
my @m = @_; |
414
|
|
|
|
|
|
|
|
415
|
6
|
|
|
|
|
24
|
my $first_group = ReorderBorderRadiusPart( @m[ 3 .. 6 ] ); |
416
|
6
|
|
|
|
|
24
|
my $second_group = ReorderBorderRadiusPart( @m[ 7 .. $#m ] ); |
417
|
|
|
|
|
|
|
|
418
|
6
|
100
|
|
|
|
16
|
if ( $second_group eq '' ) { |
419
|
4
|
|
|
|
|
22
|
return sprintf( '%sborder-radius%s%s', $m[1], $m[2], $first_group ); |
420
|
|
|
|
|
|
|
} |
421
|
|
|
|
|
|
|
else { |
422
|
2
|
|
|
|
|
25
|
return sprintf( '%sborder-radius%s%s / %s', $m[1], $m[2], $first_group, $second_group ); |
423
|
|
|
|
|
|
|
} |
424
|
|
|
|
|
|
|
} |
425
|
|
|
|
|
|
|
|
426
|
|
|
|
|
|
|
sub CalculateNewBackgroundPosition { |
427
|
13
|
|
|
13
|
0
|
60
|
my @m = @_; |
428
|
|
|
|
|
|
|
|
429
|
13
|
|
|
|
|
30
|
my $new_x = 100 - $m[4]; |
430
|
13
|
100
|
|
|
|
27
|
my $position_string = defined( $m[1] ) ? $m[1] : ''; |
431
|
|
|
|
|
|
|
|
432
|
13
|
|
|
|
|
97
|
return sprintf( 'background%s%s%s%s%%%s', $position_string, $m[2], $m[3], $new_x, $m[5] ); |
433
|
|
|
|
|
|
|
} |
434
|
|
|
|
|
|
|
|
435
|
|
|
|
|
|
|
sub CalculateNewBackgroundPositionX { |
436
|
2
|
|
|
2
|
0
|
9
|
my @m = @_; |
437
|
|
|
|
|
|
|
|
438
|
2
|
|
|
|
|
4
|
my $new_x = 100 - $m[2]; |
439
|
|
|
|
|
|
|
|
440
|
2
|
|
|
|
|
17
|
return sprintf( 'background-position-x%s%s%%', $m[1], $new_x ); |
441
|
|
|
|
|
|
|
} |
442
|
|
|
|
|
|
|
|
443
|
|
|
|
|
|
|
sub CalculateNewBackgroundLengthPosition { |
444
|
1
|
50
|
|
1
|
0
|
6
|
my $ignore_bad_bgp = @_ > 7 ? pop( @_ ) : 0; |
445
|
1
|
|
|
|
|
10
|
my @m = @_; |
446
|
|
|
|
|
|
|
|
447
|
1
|
50
|
|
|
|
10
|
unless ( $m[4] =~ $ZERO_LENGTH ) { |
448
|
0
|
|
|
|
|
0
|
warn( "Unmirrorable horizontal value $m[4]: $m[0]" ); |
449
|
0
|
0
|
|
|
|
0
|
return $ignore_bad_bgp ? $m[0] : undef; |
450
|
|
|
|
|
|
|
} |
451
|
|
|
|
|
|
|
|
452
|
1
|
50
|
|
|
|
6
|
my $position_string = defined( $m[1] ) ? $m[1] : ''; |
453
|
|
|
|
|
|
|
|
454
|
1
|
|
|
|
|
17
|
return sprintf( 'background%s%s%s100%%%s', $position_string, $m[2], $m[3], $m[5] ); |
455
|
|
|
|
|
|
|
|
456
|
|
|
|
|
|
|
} |
457
|
|
|
|
|
|
|
|
458
|
|
|
|
|
|
|
sub CalculateNewBackgroundLengthPositionX { |
459
|
1
|
50
|
|
1
|
0
|
5
|
my $ignore_bad_bgp = @_ > 3 ? pop( @_ ) : 0; |
460
|
1
|
|
|
|
|
6
|
my @m = @_; |
461
|
|
|
|
|
|
|
|
462
|
1
|
50
|
|
|
|
8
|
unless ( $m[2] =~ $ZERO_LENGTH ) { |
463
|
0
|
|
|
|
|
0
|
warn( "Unmirrorable horizontal value $m[2]: $m[0]" ); |
464
|
0
|
0
|
|
|
|
0
|
return $ignore_bad_bgp ? $m[0] : undef; |
465
|
|
|
|
|
|
|
} |
466
|
|
|
|
|
|
|
|
467
|
1
|
|
|
|
|
17
|
return sprintf( 'background-position-x%s100%%', $m[1] ); |
468
|
|
|
|
|
|
|
} |
469
|
|
|
|
|
|
|
|
470
|
|
|
|
|
|
|
sub FixBorderRadius { |
471
|
103
|
|
|
103
|
0
|
160
|
my ( $line ) = @_; |
472
|
|
|
|
|
|
|
|
473
|
|
|
|
|
|
|
# full match not needed, leave undef |
474
|
103
|
|
|
|
|
3097
|
$line =~ s!$BORDER_RADIUS_RE!ReorderBorderRadius(undef,$1,$2,$3,$4,$5,$6,$7,$8,$9,$10)!egms; |
|
5
|
|
|
|
|
20
|
|
475
|
|
|
|
|
|
|
|
476
|
103
|
|
|
|
|
173
|
return $line; |
477
|
|
|
|
|
|
|
} |
478
|
|
|
|
|
|
|
|
479
|
|
|
|
|
|
|
sub FixFourPartNotation { |
480
|
103
|
|
|
103
|
0
|
255
|
my $line = shift; |
481
|
|
|
|
|
|
|
|
482
|
103
|
|
|
|
|
2476
|
$line =~ s!$FOUR_NOTATION_QUANTITY_RE!$1 $4 $3 $2!g; |
483
|
103
|
|
|
|
|
380
|
$line =~ s!$FOUR_NOTATION_COLOR_RE!$1$2 $5 $4 $3!g; |
484
|
|
|
|
|
|
|
|
485
|
103
|
|
|
|
|
200
|
return $line; |
486
|
|
|
|
|
|
|
} |
487
|
|
|
|
|
|
|
|
488
|
|
|
|
|
|
|
sub ChangeLeftToRightToLeft { |
489
|
102
|
|
|
102
|
1
|
231
|
my ( $lines, $swap_ltr_rtl_in_url, $swap_left_right_in_url, $ignore_bad_bgp ) = @_; |
490
|
|
|
|
|
|
|
|
491
|
102
|
50
|
|
|
|
334
|
my $line = join( $TOKEN_LINES, ref( $lines ) ? @$lines : $lines ); |
492
|
|
|
|
|
|
|
|
493
|
|
|
|
|
|
|
# Tokenize any single line rules with the /* noflip */ annotation. |
494
|
102
|
|
|
|
|
271
|
my $noflip_single_tokenizer = CSS::Orientation::Tokenizer->new( $NOFLIP_SINGLE_RE, 'NOFLIP_SINGLE' ); |
495
|
102
|
|
|
|
|
209
|
$line = $noflip_single_tokenizer->tokenize( $line ); |
496
|
|
|
|
|
|
|
|
497
|
|
|
|
|
|
|
# Tokenize any class rules with the /* noflip */ annotation. |
498
|
102
|
|
|
|
|
257
|
my $noflip_class_tokenizer = CSS::Orientation::Tokenizer->new( $NOFLIP_CLASS_RE, 'NOFLIP_CLASS' ); |
499
|
102
|
|
|
|
|
230
|
$line = $noflip_class_tokenizer->tokenize( $line ); |
500
|
|
|
|
|
|
|
|
501
|
|
|
|
|
|
|
# Tokenize the comments so we can preserve them through the changes. |
502
|
102
|
|
|
|
|
259
|
my $comment_tokenizer = CSS::Orientation::Tokenizer->new( $COMMENT_RE, 'C' ); |
503
|
102
|
|
|
|
|
189
|
$line = $comment_tokenizer->tokenize( $line ); |
504
|
|
|
|
|
|
|
|
505
|
|
|
|
|
|
|
# Tokenize gradients since we don't want to mirror the values inside |
506
|
102
|
|
|
|
|
245
|
my $gradient_tokenizer = CSS::Orientation::Tokenizer->new( $GRADIENT_RE, 'GRADIENT' ); |
507
|
102
|
|
|
|
|
174
|
$line = $gradient_tokenizer->tokenize( $line ); |
508
|
|
|
|
|
|
|
|
509
|
|
|
|
|
|
|
# Here starteth the various left/right orientation fixes. |
510
|
102
|
|
|
|
|
354
|
$line = FixBodyDirectionLtrAndRtl( $line ); |
511
|
|
|
|
|
|
|
|
512
|
102
|
100
|
|
|
|
236
|
if ( $swap_left_right_in_url ) { |
513
|
11
|
|
|
|
|
23
|
$line = FixLeftAndRightInUrl( $line ); |
514
|
|
|
|
|
|
|
} |
515
|
|
|
|
|
|
|
|
516
|
102
|
100
|
|
|
|
518
|
if ( $swap_ltr_rtl_in_url ) { |
517
|
11
|
|
|
|
|
19
|
$line = FixLtrAndRtlInUrl( $line ); |
518
|
|
|
|
|
|
|
} |
519
|
|
|
|
|
|
|
|
520
|
102
|
|
|
|
|
177
|
$line = FixLeftAndRight( $line ); |
521
|
102
|
|
|
|
|
195
|
$line = FixCursorProperties( $line ); |
522
|
|
|
|
|
|
|
|
523
|
102
|
|
|
|
|
266
|
$line = FixBorderRadius( $line ); |
524
|
|
|
|
|
|
|
# Since FourPartNotation conflicts with BorderRadius, we tokenize border-radius properties here. |
525
|
102
|
|
|
|
|
252
|
my $border_radius_tokenizer = CSS::Orientation::Tokenizer->new( $BORDER_RADIUS_TOKENIZER_RE, 'BORDER_RADIUS' ); |
526
|
102
|
|
|
|
|
194
|
$line = $border_radius_tokenizer->tokenize( $line ); |
527
|
102
|
|
|
|
|
184
|
$line = FixFourPartNotation( $line ); |
528
|
102
|
|
|
|
|
251
|
$line = $border_radius_tokenizer->detokenize( $line ); |
529
|
|
|
|
|
|
|
|
530
|
102
|
|
|
|
|
193
|
$line = FixBackgroundPosition( $line, $ignore_bad_bgp ); |
531
|
|
|
|
|
|
|
|
532
|
102
|
50
|
|
|
|
300
|
unless ( defined( $line ) ) { |
533
|
0
|
|
|
|
|
0
|
return undef; |
534
|
|
|
|
|
|
|
} |
535
|
|
|
|
|
|
|
|
536
|
102
|
|
|
|
|
199
|
$line = $gradient_tokenizer->detokenize( $line ); |
537
|
|
|
|
|
|
|
|
538
|
|
|
|
|
|
|
# DeTokenize the single line noflips. |
539
|
102
|
|
|
|
|
217
|
$line = $noflip_single_tokenizer->detokenize( $line ); |
540
|
|
|
|
|
|
|
|
541
|
|
|
|
|
|
|
# DeTokenize the class-level noflips. |
542
|
102
|
|
|
|
|
191
|
$line = $noflip_class_tokenizer->detokenize( $line ); |
543
|
|
|
|
|
|
|
|
544
|
|
|
|
|
|
|
# DeTokenize the comments. |
545
|
102
|
|
|
|
|
188
|
$line = $comment_tokenizer->detokenize( $line ); |
546
|
|
|
|
|
|
|
|
547
|
|
|
|
|
|
|
# Rejoin the lines back together. |
548
|
102
|
|
|
|
|
857
|
my @lines = split( $TOKEN_LINES, $line ); |
549
|
|
|
|
|
|
|
|
550
|
102
|
50
|
|
|
|
964
|
return ref( $lines ) ? \@lines : $lines[0]; |
551
|
|
|
|
|
|
|
} |
552
|
|
|
|
|
|
|
|
553
|
|
|
|
|
|
|
sub change { |
554
|
0
|
|
|
0
|
1
|
0
|
shift; |
555
|
0
|
|
|
|
|
0
|
ChangeLeftToRightToLeft( @_ ); |
556
|
|
|
|
|
|
|
} |
557
|
|
|
|
|
|
|
|
558
|
|
|
|
|
|
|
1; |
559
|
|
|
|
|
|
|
|
560
|
|
|
|
|
|
|
package CSS::Orientation::Tokenizer; |
561
|
|
|
|
|
|
|
|
562
|
12
|
|
|
12
|
|
128
|
use strict; |
|
12
|
|
|
|
|
23
|
|
|
12
|
|
|
|
|
528
|
|
563
|
12
|
|
|
12
|
|
64
|
use warnings; |
|
12
|
|
|
|
|
21
|
|
|
12
|
|
|
|
|
4526
|
|
564
|
|
|
|
|
|
|
|
565
|
|
|
|
|
|
|
sub new { |
566
|
510
|
|
|
510
|
|
779
|
my ( $class, $re, $string ) = @_; |
567
|
510
|
|
|
|
|
2238
|
my $self = bless( { |
568
|
|
|
|
|
|
|
're' => $re, |
569
|
|
|
|
|
|
|
'string' => $string, |
570
|
|
|
|
|
|
|
'originals' => [], |
571
|
|
|
|
|
|
|
}, $class ); |
572
|
|
|
|
|
|
|
|
573
|
510
|
|
|
|
|
911
|
return $self; |
574
|
|
|
|
|
|
|
} |
575
|
|
|
|
|
|
|
|
576
|
|
|
|
|
|
|
sub tokenize { |
577
|
510
|
|
|
510
|
|
691
|
my ( $self, $line ) = @_; |
578
|
|
|
|
|
|
|
|
579
|
510
|
|
|
|
|
5065
|
$line =~ s!$self->{re}! |
580
|
23
|
|
|
|
|
109
|
$CSS::Orientation::TOKEN_DELIMITER . |
581
|
|
|
|
|
|
|
$self->{string} . '_' . |
582
|
23
|
|
|
|
|
48
|
push( @{ $self->{originals} }, $1 ) . |
583
|
|
|
|
|
|
|
$CSS::Orientation::TOKEN_DELIMITER |
584
|
|
|
|
|
|
|
!egx; |
585
|
|
|
|
|
|
|
|
586
|
510
|
|
|
|
|
976
|
return $line; |
587
|
|
|
|
|
|
|
} |
588
|
|
|
|
|
|
|
|
589
|
|
|
|
|
|
|
sub detokenize { |
590
|
510
|
|
|
510
|
|
742
|
my ( $self, $line ) = @_; |
591
|
|
|
|
|
|
|
|
592
|
510
|
|
|
|
|
7474
|
$line =~ s! |
593
|
|
|
|
|
|
|
$CSS::Orientation::TOKEN_DELIMITER |
594
|
|
|
|
|
|
|
$self->{string} _ |
595
|
|
|
|
|
|
|
([0-9]+) |
596
|
|
|
|
|
|
|
$CSS::Orientation::TOKEN_DELIMITER |
597
|
|
|
|
|
|
|
! |
598
|
23
|
50
|
33
|
|
|
80
|
$1 > 0 && $1 <= @{ $self->{originals} } ? $self->{originals}[$1-1] : '' |
599
|
|
|
|
|
|
|
!egx; |
600
|
|
|
|
|
|
|
|
601
|
510
|
|
|
|
|
1261
|
return $line; |
602
|
|
|
|
|
|
|
} |
603
|
|
|
|
|
|
|
|
604
|
|
|
|
|
|
|
1; |
605
|
|
|
|
|
|
|
|
606
|
|
|
|
|
|
|
__END__ |