cataract 0.2.5 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.github/workflows/test.yml +6 -6
- data/.gitignore +17 -3
- data/CHANGELOG.md +19 -1
- data/Gemfile +2 -2
- data/examples/css_analyzer/analyzer.rb +9 -3
- data/examples/css_analyzer/analyzers/base.rb +1 -1
- data/ext/cataract/cataract.c +247 -454
- data/ext/cataract/cataract.h +126 -15
- data/ext/cataract/css_parser.c +782 -788
- data/ext/cataract/extconf.rb +1 -2
- data/ext/cataract/flatten.c +279 -991
- data/ext/cataract/shorthand_expander.c +80 -102
- data/ext/cataract_color/color_conversion.c +1 -1
- data/lib/cataract/declarations.rb +13 -7
- data/lib/cataract/import_resolver.rb +36 -16
- data/lib/cataract/pure/byte_constants.rb +0 -1
- data/lib/cataract/pure/flatten.rb +143 -145
- data/lib/cataract/pure/parser.rb +495 -422
- data/lib/cataract/pure/serializer.rb +109 -104
- data/lib/cataract/pure/specificity.rb +112 -156
- data/lib/cataract/pure.rb +0 -7
- data/lib/cataract/stylesheet.rb +460 -412
- data/lib/cataract/version.rb +1 -1
- metadata +2 -13
- data/ext/cataract/import_scanner.c +0 -174
- data/ext/cataract_old/cataract.c +0 -393
- data/ext/cataract_old/cataract.h +0 -250
- data/ext/cataract_old/css_parser.c +0 -933
- data/ext/cataract_old/extconf.rb +0 -67
- data/ext/cataract_old/import_scanner.c +0 -174
- data/ext/cataract_old/merge.c +0 -776
- data/ext/cataract_old/shorthand_expander.c +0 -902
- data/ext/cataract_old/specificity.c +0 -213
- data/ext/cataract_old/stylesheet.c +0 -290
- data/ext/cataract_old/value_splitter.c +0 -116
|
@@ -99,7 +99,14 @@ module Cataract
|
|
|
99
99
|
SIDE_RIGHT = 'right'
|
|
100
100
|
SIDE_BOTTOM = 'bottom'
|
|
101
101
|
SIDE_LEFT = 'left'
|
|
102
|
-
|
|
102
|
+
|
|
103
|
+
# Maps a border side name to its [width, style, color] property constants
|
|
104
|
+
BORDER_SIDE_PROPS = {
|
|
105
|
+
SIDE_TOP => [PROP_BORDER_TOP_WIDTH, PROP_BORDER_TOP_STYLE, PROP_BORDER_TOP_COLOR],
|
|
106
|
+
SIDE_RIGHT => [PROP_BORDER_RIGHT_WIDTH, PROP_BORDER_RIGHT_STYLE, PROP_BORDER_RIGHT_COLOR],
|
|
107
|
+
SIDE_BOTTOM => [PROP_BORDER_BOTTOM_WIDTH, PROP_BORDER_BOTTOM_STYLE, PROP_BORDER_BOTTOM_COLOR],
|
|
108
|
+
SIDE_LEFT => [PROP_BORDER_LEFT_WIDTH, PROP_BORDER_LEFT_STYLE, PROP_BORDER_LEFT_COLOR]
|
|
109
|
+
}.freeze
|
|
103
110
|
|
|
104
111
|
FONT_PROPERTIES = [
|
|
105
112
|
PROP_FONT_STYLE,
|
|
@@ -163,11 +170,38 @@ module Cataract
|
|
|
163
170
|
# @param mutate [Boolean] If true, mutate the stylesheet; otherwise create new one
|
|
164
171
|
# @return [Stylesheet] Merged stylesheet
|
|
165
172
|
def self.flatten(stylesheet, mutate: false)
|
|
166
|
-
|
|
173
|
+
at_rules, regular_rules = partition_at_rules(stylesheet.rules)
|
|
174
|
+
|
|
175
|
+
expand_all_shorthands!(regular_rules)
|
|
176
|
+
merged_rules = merge_rules_by_selector_and_media(regular_rules)
|
|
177
|
+
merged_rules.each { |rule| recreate_shorthands!(rule) }
|
|
178
|
+
|
|
179
|
+
# Assign new IDs before checking divergence (so we can build correct selector_lists hash)
|
|
180
|
+
merged_rules.each_with_index { |rule, i| rule.id = i }
|
|
181
|
+
|
|
182
|
+
selector_lists = build_selector_lists(stylesheet, merged_rules)
|
|
183
|
+
|
|
184
|
+
# Add passthrough AtRules to output
|
|
185
|
+
merged_rules.concat(at_rules)
|
|
186
|
+
|
|
187
|
+
media_queries = stylesheet.instance_variable_get(:@media_queries)
|
|
188
|
+
media_query_lists = stylesheet.instance_variable_get(:@_media_query_lists)
|
|
189
|
+
new_media_index = rebuild_media_index(merged_rules, media_queries, media_query_lists)
|
|
190
|
+
|
|
191
|
+
build_result(stylesheet, merged_rules, new_media_index, media_queries, media_query_lists, selector_lists,
|
|
192
|
+
mutate)
|
|
193
|
+
end
|
|
194
|
+
|
|
195
|
+
# Separate AtRules (pass-through, unaffected by cascade) from regular
|
|
196
|
+
# Rules (to merge).
|
|
197
|
+
#
|
|
198
|
+
# @param rules [Array<Rule, AtRule>]
|
|
199
|
+
# @return [Array(Array<AtRule>, Array<Rule>)]
|
|
200
|
+
def self.partition_at_rules(rules)
|
|
167
201
|
at_rules = []
|
|
168
202
|
regular_rules = []
|
|
169
203
|
|
|
170
|
-
|
|
204
|
+
rules.each do |rule|
|
|
171
205
|
if rule.at_rule?
|
|
172
206
|
at_rules << rule
|
|
173
207
|
else
|
|
@@ -175,11 +209,20 @@ module Cataract
|
|
|
175
209
|
end
|
|
176
210
|
end
|
|
177
211
|
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
212
|
+
[at_rules, regular_rules]
|
|
213
|
+
end
|
|
214
|
+
|
|
215
|
+
# Expand shorthands in regular rules only (AtRules don't have declarations).
|
|
216
|
+
# Mutates each rule's declarations in place.
|
|
217
|
+
#
|
|
218
|
+
# NOTE: Using manual each + concat instead of .flat_map for performance.
|
|
219
|
+
# The concise form (.flat_map) is ~5-10% slower depending on number of shorthands to expand.
|
|
220
|
+
# NOTE: Fast-path check for shorthands (Hash lookup) avoids calling expand_shorthand
|
|
221
|
+
# for declarations that are not shorthands (~20% faster than calling method unconditionally).
|
|
222
|
+
#
|
|
223
|
+
# @param regular_rules [Array<Rule>]
|
|
224
|
+
# @return [void]
|
|
225
|
+
def self.expand_all_shorthands!(regular_rules)
|
|
183
226
|
regular_rules.each do |rule|
|
|
184
227
|
expanded = []
|
|
185
228
|
rule.declarations.each do |decl|
|
|
@@ -191,58 +234,55 @@ module Cataract
|
|
|
191
234
|
end
|
|
192
235
|
rule.declarations.replace(expanded)
|
|
193
236
|
end
|
|
237
|
+
end
|
|
194
238
|
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
239
|
+
# Group rules by (selector, media_query_id) and merge each group
|
|
240
|
+
# according to CSS cascade rules. Rules with the same selector but
|
|
241
|
+
# different media contexts are NOT merged together.
|
|
242
|
+
#
|
|
243
|
+
# @param regular_rules [Array<Rule>]
|
|
244
|
+
# @return [Array<Rule>] Merged rules, one per (selector, media_query_id) group
|
|
245
|
+
def self.merge_rules_by_selector_and_media(regular_rules)
|
|
199
246
|
# NOTE: Using manual each instead of .group_by to avoid intermediate hash allocation.
|
|
200
247
|
by_selector_and_media = {}
|
|
201
248
|
regular_rules.each do |rule|
|
|
202
|
-
|
|
203
|
-
key = [rule.selector, media_query_id]
|
|
249
|
+
key = [rule.selector, rule.media_query_id]
|
|
204
250
|
(by_selector_and_media[key] ||= []) << rule
|
|
205
251
|
end
|
|
206
252
|
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
by_selector_and_media.each do |(_selector, media_query_id), rules|
|
|
253
|
+
merged_rules = []
|
|
254
|
+
by_selector_and_media.each_value do |rules|
|
|
210
255
|
merged_rule = flatten_rules_for_selector(rules.first.selector, rules)
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
# Only build mapping for rules that are in media queries
|
|
214
|
-
if media_query_id
|
|
215
|
-
new_index = merged_rules.length
|
|
216
|
-
|
|
217
|
-
rules.each do |old_rule|
|
|
218
|
-
old_to_new_id[old_rule.id] = new_index
|
|
219
|
-
end
|
|
220
|
-
end
|
|
221
|
-
merged_rules << merged_rule
|
|
256
|
+
merged_rules << merged_rule if merged_rule
|
|
222
257
|
end
|
|
258
|
+
merged_rules
|
|
259
|
+
end
|
|
223
260
|
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
261
|
+
# Handle selector list divergence: remove rules from selector lists if
|
|
262
|
+
# declarations no longer match. This makes selector_list_id
|
|
263
|
+
# authoritative - if set, declarations MUST be identical. Only
|
|
264
|
+
# processed if selector_lists is enabled in the stylesheet's parser
|
|
265
|
+
# options.
|
|
266
|
+
#
|
|
267
|
+
# @param stylesheet [Stylesheet] Source stylesheet (for parser options)
|
|
268
|
+
# @param merged_rules [Array<Rule>] Merged rules, already assigned final IDs
|
|
269
|
+
# @return [Hash] list_id => Array of rule IDs, empty if not tracking selector lists
|
|
270
|
+
def self.build_selector_lists(stylesheet, merged_rules)
|
|
233
271
|
selector_lists = {}
|
|
234
272
|
parser_options = stylesheet.instance_variable_get(:@parser_options) || {}
|
|
235
|
-
if parser_options[:selector_lists]
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
# Add passthrough AtRules to output
|
|
240
|
-
merged_rules.concat(at_rules)
|
|
273
|
+
update_selector_lists_for_divergence!(merged_rules, selector_lists) if parser_options[:selector_lists]
|
|
274
|
+
selector_lists
|
|
275
|
+
end
|
|
241
276
|
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
277
|
+
# Rebuild media_index from rules' media_query_id. This ensures
|
|
278
|
+
# media_index is consistent with the MediaQuery objects, rather than
|
|
279
|
+
# trying to remap the stylesheet's existing (now-stale) media_index.
|
|
280
|
+
#
|
|
281
|
+
# @param merged_rules [Array<Rule, AtRule>] Final rules, including passthrough AtRules
|
|
282
|
+
# @param media_queries [Array<MediaQuery>]
|
|
283
|
+
# @param media_query_lists [Hash{Integer => Array<Integer>}] list_id => media_query_ids
|
|
284
|
+
# @return [Hash{Symbol => Array<Integer>}] media type => rule IDs
|
|
285
|
+
def self.rebuild_media_index(merged_rules, media_queries, media_query_lists)
|
|
246
286
|
new_media_index = {}
|
|
247
287
|
|
|
248
288
|
# Build reverse map: media_query_id => list_id (one-time cost)
|
|
@@ -265,34 +305,37 @@ module Cataract
|
|
|
265
305
|
mq = media_queries[mq_id]
|
|
266
306
|
next unless mq
|
|
267
307
|
|
|
268
|
-
|
|
269
|
-
new_media_index[
|
|
270
|
-
new_media_index[media_type] << rule.id
|
|
308
|
+
new_media_index[mq.type] ||= []
|
|
309
|
+
new_media_index[mq.type] << rule.id
|
|
271
310
|
end
|
|
272
311
|
else
|
|
273
312
|
# Single media query - just index under its type
|
|
274
313
|
mq = media_queries[rule.media_query_id]
|
|
275
314
|
next unless mq
|
|
276
315
|
|
|
277
|
-
|
|
278
|
-
new_media_index[
|
|
279
|
-
new_media_index[media_type] << rule.id
|
|
316
|
+
new_media_index[mq.type] ||= []
|
|
317
|
+
new_media_index[mq.type] << rule.id
|
|
280
318
|
end
|
|
281
319
|
end
|
|
282
320
|
|
|
283
321
|
# Deduplicate arrays once at the end
|
|
284
322
|
new_media_index.each_value(&:uniq!)
|
|
323
|
+
new_media_index
|
|
324
|
+
end
|
|
285
325
|
|
|
286
|
-
|
|
326
|
+
# Build the final result: either mutate the input stylesheet in place,
|
|
327
|
+
# or construct a new one, with the merged rules/media_index/selector_lists.
|
|
328
|
+
#
|
|
329
|
+
# @return [Stylesheet]
|
|
330
|
+
def self.build_result(stylesheet, merged_rules, new_media_index, media_queries, media_query_lists,
|
|
331
|
+
selector_lists, mutate)
|
|
287
332
|
if mutate
|
|
288
333
|
stylesheet.instance_variable_set(:@rules, merged_rules)
|
|
289
334
|
stylesheet.instance_variable_set(:@media_index, new_media_index)
|
|
290
335
|
# @media_queries and @_media_query_lists stay the same - preserved from input
|
|
291
|
-
# Update selector lists with divergence tracking
|
|
292
336
|
stylesheet.instance_variable_set(:@_selector_lists, selector_lists)
|
|
293
337
|
stylesheet
|
|
294
338
|
else
|
|
295
|
-
# Create new Stylesheet with merged rules
|
|
296
339
|
result = Stylesheet.new
|
|
297
340
|
result.instance_variable_set(:@rules, merged_rules)
|
|
298
341
|
result.instance_variable_set(:@media_index, new_media_index)
|
|
@@ -553,39 +596,12 @@ module Cataract
|
|
|
553
596
|
# Extract side from property name (e.g., "border-top" -> "top")
|
|
554
597
|
side = decl.property.byteslice(7..-1) # Skip "border-" prefix
|
|
555
598
|
width, style, color = parse_border_value(decl.value)
|
|
599
|
+
width_prop, style_prop, color_prop = BORDER_SIDE_PROPS[side]
|
|
556
600
|
|
|
557
601
|
result = []
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
if
|
|
561
|
-
width_prop = case side
|
|
562
|
-
when SIDE_TOP then PROP_BORDER_TOP_WIDTH
|
|
563
|
-
when SIDE_RIGHT then PROP_BORDER_RIGHT_WIDTH
|
|
564
|
-
when SIDE_BOTTOM then PROP_BORDER_BOTTOM_WIDTH
|
|
565
|
-
when SIDE_LEFT then PROP_BORDER_LEFT_WIDTH
|
|
566
|
-
end
|
|
567
|
-
result << Declaration.new(width_prop, width, decl.important)
|
|
568
|
-
end
|
|
569
|
-
|
|
570
|
-
if style
|
|
571
|
-
style_prop = case side
|
|
572
|
-
when SIDE_TOP then PROP_BORDER_TOP_STYLE
|
|
573
|
-
when SIDE_RIGHT then PROP_BORDER_RIGHT_STYLE
|
|
574
|
-
when SIDE_BOTTOM then PROP_BORDER_BOTTOM_STYLE
|
|
575
|
-
when SIDE_LEFT then PROP_BORDER_LEFT_STYLE
|
|
576
|
-
end
|
|
577
|
-
result << Declaration.new(style_prop, style, decl.important)
|
|
578
|
-
end
|
|
579
|
-
|
|
580
|
-
if color
|
|
581
|
-
color_prop = case side
|
|
582
|
-
when SIDE_TOP then PROP_BORDER_TOP_COLOR
|
|
583
|
-
when SIDE_RIGHT then PROP_BORDER_RIGHT_COLOR
|
|
584
|
-
when SIDE_BOTTOM then PROP_BORDER_BOTTOM_COLOR
|
|
585
|
-
when SIDE_LEFT then PROP_BORDER_LEFT_COLOR
|
|
586
|
-
end
|
|
587
|
-
result << Declaration.new(color_prop, color, decl.important)
|
|
588
|
-
end
|
|
602
|
+
result << Declaration.new(width_prop, width, decl.important) if width
|
|
603
|
+
result << Declaration.new(style_prop, style, decl.important) if style
|
|
604
|
+
result << Declaration.new(color_prop, color, decl.important) if color
|
|
589
605
|
|
|
590
606
|
result
|
|
591
607
|
end
|
|
@@ -644,12 +660,8 @@ module Cataract
|
|
|
644
660
|
[width, style, color]
|
|
645
661
|
end
|
|
646
662
|
|
|
647
|
-
# Check if value
|
|
648
|
-
def self.
|
|
649
|
-
# Check for numeric values or width keywords
|
|
650
|
-
return true if BORDER_WIDTH_KEYWORDS.include?(value)
|
|
651
|
-
|
|
652
|
-
# Check if value contains a digit (byte-by-byte)
|
|
663
|
+
# Check if value contains a digit (byte-by-byte)
|
|
664
|
+
def self.contains_digit?(value)
|
|
653
665
|
i = 0
|
|
654
666
|
len = value.bytesize
|
|
655
667
|
while i < len
|
|
@@ -662,6 +674,14 @@ module Cataract
|
|
|
662
674
|
false
|
|
663
675
|
end
|
|
664
676
|
|
|
677
|
+
# Check if value looks like a border width
|
|
678
|
+
def self.is_border_width?(value)
|
|
679
|
+
# Check for numeric values or width keywords
|
|
680
|
+
return true if BORDER_WIDTH_KEYWORDS.include?(value)
|
|
681
|
+
|
|
682
|
+
contains_digit?(value)
|
|
683
|
+
end
|
|
684
|
+
|
|
665
685
|
# Check if value is a border style
|
|
666
686
|
def self.is_border_style?(value)
|
|
667
687
|
BORDER_STYLE_KEYWORDS.include?(value)
|
|
@@ -702,7 +722,7 @@ module Cataract
|
|
|
702
722
|
j = 0
|
|
703
723
|
len = size_part.bytesize
|
|
704
724
|
while j < len
|
|
705
|
-
if size_part.getbyte(j) ==
|
|
725
|
+
if size_part.getbyte(j) == BYTE_SLASH
|
|
706
726
|
slash_idx = j
|
|
707
727
|
break
|
|
708
728
|
end
|
|
@@ -755,14 +775,8 @@ module Cataract
|
|
|
755
775
|
# Check if value is a font size
|
|
756
776
|
def self.is_font_size?(value)
|
|
757
777
|
# Has digit or is a keyword
|
|
758
|
-
|
|
759
|
-
len = value.bytesize
|
|
760
|
-
while i < len
|
|
761
|
-
byte = value.getbyte(i)
|
|
762
|
-
return true if byte >= BYTE_DIGIT_0 && byte <= BYTE_DIGIT_9
|
|
778
|
+
return true if contains_digit?(value)
|
|
763
779
|
|
|
764
|
-
i += 1
|
|
765
|
-
end
|
|
766
780
|
FONT_SIZE_KEYWORDS.include?(value)
|
|
767
781
|
end
|
|
768
782
|
|
|
@@ -779,14 +793,8 @@ module Cataract
|
|
|
779
793
|
# Check if value is a font weight
|
|
780
794
|
def self.is_font_weight?(value)
|
|
781
795
|
# Check for numeric weights like 400, 700
|
|
782
|
-
|
|
783
|
-
len = value.bytesize
|
|
784
|
-
while i < len
|
|
785
|
-
byte = value.getbyte(i)
|
|
786
|
-
return true if byte >= BYTE_DIGIT_0 && byte <= BYTE_DIGIT_9
|
|
796
|
+
return true if contains_digit?(value)
|
|
787
797
|
|
|
788
|
-
i += 1
|
|
789
|
-
end
|
|
790
798
|
FONT_WEIGHT_KEYWORDS.include?(value)
|
|
791
799
|
end
|
|
792
800
|
|
|
@@ -849,14 +857,13 @@ module Cataract
|
|
|
849
857
|
# Check if value is a position value (for background-position)
|
|
850
858
|
def self.is_position_value?(value)
|
|
851
859
|
return true if BACKGROUND_POSITION_KEYWORDS.include?(value)
|
|
860
|
+
return true if contains_digit?(value)
|
|
852
861
|
|
|
853
|
-
# Check for '%'
|
|
862
|
+
# Check for '%'
|
|
854
863
|
i = 0
|
|
855
864
|
len = value.bytesize
|
|
856
865
|
while i < len
|
|
857
|
-
|
|
858
|
-
return true if byte == BYTE_PERCENT
|
|
859
|
-
return true if byte >= BYTE_DIGIT_0 && byte <= BYTE_DIGIT_9
|
|
866
|
+
return true if value.getbyte(i) == BYTE_PERCENT
|
|
860
867
|
|
|
861
868
|
i += 1
|
|
862
869
|
end
|
|
@@ -894,6 +901,14 @@ module Cataract
|
|
|
894
901
|
result.empty? ? [decl] : result
|
|
895
902
|
end
|
|
896
903
|
|
|
904
|
+
# Remove the individual longhand declarations a shorthand replaces and
|
|
905
|
+
# append the shorthand declaration in their place.
|
|
906
|
+
# Note: We append rather than insert at original position to match C implementation behavior
|
|
907
|
+
def self.replace_with_shorthand!(rule, longhand_props, shorthand_prop, value, important)
|
|
908
|
+
rule.declarations.reject! { |d| longhand_props.include?(d.property) }
|
|
909
|
+
rule.declarations << Declaration.new(shorthand_prop, value, important)
|
|
910
|
+
end
|
|
911
|
+
|
|
897
912
|
# Recreate shorthand properties where possible (mutates declarations)
|
|
898
913
|
#
|
|
899
914
|
# @param rule [Rule] Rule to recreate shorthands in
|
|
@@ -943,10 +958,7 @@ module Cataract
|
|
|
943
958
|
# Create optimized shorthand
|
|
944
959
|
shorthand_value = optimize_four_sides(values)
|
|
945
960
|
|
|
946
|
-
|
|
947
|
-
# Note: We append rather than insert at original position to match C implementation behavior
|
|
948
|
-
rule.declarations.reject! { |d| MARGIN_SIDES.include?(d.property) }
|
|
949
|
-
rule.declarations << Declaration.new(PROP_MARGIN, shorthand_value, important)
|
|
961
|
+
replace_with_shorthand!(rule, MARGIN_SIDES, PROP_MARGIN, shorthand_value, important)
|
|
950
962
|
end
|
|
951
963
|
|
|
952
964
|
# Try to recreate padding shorthand
|
|
@@ -969,10 +981,7 @@ module Cataract
|
|
|
969
981
|
|
|
970
982
|
shorthand_value = optimize_four_sides(values)
|
|
971
983
|
|
|
972
|
-
|
|
973
|
-
# Note: We append rather than insert at original position to match C implementation behavior
|
|
974
|
-
rule.declarations.reject! { |d| PADDING_SIDES.include?(d.property) }
|
|
975
|
-
rule.declarations << Declaration.new(PROP_PADDING, shorthand_value, important)
|
|
984
|
+
replace_with_shorthand!(rule, PADDING_SIDES, PROP_PADDING, shorthand_value, important)
|
|
976
985
|
end
|
|
977
986
|
|
|
978
987
|
# Helper: Check if all declarations have same value and importance
|
|
@@ -1037,10 +1046,7 @@ module Cataract
|
|
|
1037
1046
|
|
|
1038
1047
|
border_value = parts.join(' ')
|
|
1039
1048
|
|
|
1040
|
-
|
|
1041
|
-
# Note: We append rather than insert at original position to match C implementation behavior
|
|
1042
|
-
rule.declarations.reject! { |d| BORDER_ALL.include?(d.property) }
|
|
1043
|
-
rule.declarations << Declaration.new(PROP_BORDER, border_value, important)
|
|
1049
|
+
replace_with_shorthand!(rule, BORDER_ALL, PROP_BORDER, border_value, important)
|
|
1044
1050
|
return
|
|
1045
1051
|
end
|
|
1046
1052
|
end
|
|
@@ -1061,8 +1067,7 @@ module Cataract
|
|
|
1061
1067
|
|
|
1062
1068
|
shorthand_value = optimize_four_sides(values)
|
|
1063
1069
|
|
|
1064
|
-
rule
|
|
1065
|
-
rule.declarations << Declaration.new(PROP_BORDER_WIDTH, shorthand_value, important)
|
|
1070
|
+
replace_with_shorthand!(rule, BORDER_WIDTHS, PROP_BORDER_WIDTH, shorthand_value, important)
|
|
1066
1071
|
end
|
|
1067
1072
|
|
|
1068
1073
|
# Recreate border-style shorthand
|
|
@@ -1075,8 +1080,7 @@ module Cataract
|
|
|
1075
1080
|
|
|
1076
1081
|
shorthand_value = optimize_four_sides(values)
|
|
1077
1082
|
|
|
1078
|
-
rule
|
|
1079
|
-
rule.declarations << Declaration.new(PROP_BORDER_STYLE, shorthand_value, important)
|
|
1083
|
+
replace_with_shorthand!(rule, BORDER_STYLES, PROP_BORDER_STYLE, shorthand_value, important)
|
|
1080
1084
|
end
|
|
1081
1085
|
|
|
1082
1086
|
# Recreate border-color shorthand
|
|
@@ -1089,8 +1093,7 @@ module Cataract
|
|
|
1089
1093
|
|
|
1090
1094
|
shorthand_value = optimize_four_sides(values)
|
|
1091
1095
|
|
|
1092
|
-
rule
|
|
1093
|
-
rule.declarations << Declaration.new(PROP_BORDER_COLOR, shorthand_value, important)
|
|
1096
|
+
replace_with_shorthand!(rule, BORDER_COLORS, PROP_BORDER_COLOR, shorthand_value, important)
|
|
1094
1097
|
end
|
|
1095
1098
|
|
|
1096
1099
|
# Optimize four-sided value representation
|
|
@@ -1176,10 +1179,7 @@ module Cataract
|
|
|
1176
1179
|
|
|
1177
1180
|
shorthand_value = parts.join(' ')
|
|
1178
1181
|
|
|
1179
|
-
|
|
1180
|
-
# Note: We append rather than insert at original position to match C implementation behavior
|
|
1181
|
-
rule.declarations.reject! { |d| FONT_PROPERTIES.include?(d.property) }
|
|
1182
|
-
rule.declarations << Declaration.new(PROP_FONT, shorthand_value, important)
|
|
1182
|
+
replace_with_shorthand!(rule, FONT_PROPERTIES, PROP_FONT, shorthand_value, important)
|
|
1183
1183
|
end
|
|
1184
1184
|
|
|
1185
1185
|
# Try to recreate background shorthand
|
|
@@ -1235,10 +1235,7 @@ module Cataract
|
|
|
1235
1235
|
parts.join(' ')
|
|
1236
1236
|
end
|
|
1237
1237
|
|
|
1238
|
-
|
|
1239
|
-
# Note: We append rather than insert at original position to match C implementation behavior
|
|
1240
|
-
rule.declarations.reject! { |d| BACKGROUND_PROPERTIES.include?(d.property) }
|
|
1241
|
-
rule.declarations << Declaration.new(PROP_BACKGROUND, shorthand_value, important)
|
|
1238
|
+
replace_with_shorthand!(rule, BACKGROUND_PROPERTIES, PROP_BACKGROUND, shorthand_value, important)
|
|
1242
1239
|
end
|
|
1243
1240
|
|
|
1244
1241
|
# Try to recreate list-style shorthand
|
|
@@ -1264,10 +1261,7 @@ module Cataract
|
|
|
1264
1261
|
|
|
1265
1262
|
shorthand_value = parts.join(' ')
|
|
1266
1263
|
|
|
1267
|
-
|
|
1268
|
-
# Note: We append rather than insert at original position to match C implementation behavior
|
|
1269
|
-
rule.declarations.reject! { |d| LIST_STYLE_PROPERTIES.include?(d.property) }
|
|
1270
|
-
rule.declarations << Declaration.new(PROP_LIST_STYLE, shorthand_value, important)
|
|
1264
|
+
replace_with_shorthand!(rule, LIST_STYLE_PROPERTIES, PROP_LIST_STYLE, shorthand_value, important)
|
|
1271
1265
|
end
|
|
1272
1266
|
|
|
1273
1267
|
# Update selector lists to remove diverged rules
|
|
@@ -1341,12 +1335,16 @@ module Cataract
|
|
|
1341
1335
|
private_class_method :flatten_rules_for_selector, :calculate_specificity,
|
|
1342
1336
|
:expand_margin, :expand_padding, :parse_four_sides, :split_on_whitespace,
|
|
1343
1337
|
:expand_border, :expand_border_side, :expand_border_width, :expand_border_style,
|
|
1344
|
-
:expand_border_color, :parse_border_value, :
|
|
1338
|
+
:expand_border_color, :parse_border_value, :contains_digit?, :is_border_width?,
|
|
1339
|
+
:is_border_style?,
|
|
1345
1340
|
:expand_font, :is_font_size?, :is_font_style?, :is_font_variant?, :is_font_weight?,
|
|
1346
1341
|
:expand_background, :starts_with_url?, :is_position_value?, :expand_list_style,
|
|
1347
|
-
:recreate_shorthands!, :recreate_margin!, :recreate_padding!,
|
|
1342
|
+
:replace_with_shorthand!, :recreate_shorthands!, :recreate_margin!, :recreate_padding!,
|
|
1343
|
+
:check_all_same?,
|
|
1348
1344
|
:recreate_border!, :recreate_border_width!, :recreate_border_style!, :recreate_border_color!,
|
|
1349
1345
|
:optimize_four_sides, :recreate_font!, :recreate_background!, :recreate_list_style!,
|
|
1350
|
-
:update_selector_lists_for_divergence!, :declarations_equal
|
|
1346
|
+
:update_selector_lists_for_divergence!, :declarations_equal?,
|
|
1347
|
+
:partition_at_rules, :expand_all_shorthands!, :merge_rules_by_selector_and_media,
|
|
1348
|
+
:build_selector_lists, :rebuild_media_index, :build_result
|
|
1351
1349
|
end
|
|
1352
1350
|
end
|