Subsetting: Handle child elements under ::first-line

This commit is contained in:
Kovid Goyal 2022-09-28 18:19:31 +05:30
parent 9bdfb5bf46
commit f1cc7ddfd9
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
3 changed files with 26 additions and 7 deletions

View File

@ -253,7 +253,17 @@ def resolve_property(style_map, elem, name):
return defvals().get(name) return defvals().get(name)
def resolve_pseudo_property(style_map, pseudo_style_map, elem, prop, name, abort_on_missing=False): def resolve_pseudo_property(style_map, pseudo_style_map, elem, prop, name, abort_on_missing=False, check_if_pseudo_applies=False, check_ancestors=False):
if check_if_pseudo_applies:
q = elem
while q is not None:
val = pseudo_style_map.get(q, {}).get(prop, {}).get(name)
if val is not None:
return True
if not check_ancestors:
break
q = q.getparent()
return False
sub_map = pseudo_style_map.get(elem) sub_map = pseudo_style_map.get(elem)
if abort_on_missing and sub_map is None: if abort_on_missing and sub_map is None:
return None return None
@ -266,5 +276,14 @@ def resolve_pseudo_property(style_map, pseudo_style_map, elem, prop, name, abort
if val is not None: if val is not None:
return val return val
if name in INHERITED: if name in INHERITED:
if check_ancestors:
q = elem.getparent()
while q is not None:
val = pseudo_style_map.get(q, {}).get(prop, {}).get(name)
if val is not None:
return val
if not check_ancestors:
break
q = q.getparent()
return resolve_property(style_map, elem, name) return resolve_property(style_map, elem, name)
return defvals().get(name) return defvals().get(name)

View File

@ -249,8 +249,7 @@ class StatsCollector:
update_usage_for_embed(font, chars) update_usage_for_embed(font, chars)
for rule in get_matching_rules(font_face_rules, font): for rule in get_matching_rules(font_face_rules, font):
self.font_stats[rule['src']] |= chars self.font_stats[rule['src']] |= chars
q = resolve_pseudo_property(elem, 'first-letter', 'font-family', abort_on_missing=True) if resolve_pseudo_property(elem, 'first-letter', 'font-family', check_if_pseudo_applies=True):
if q is not None:
font = get_font_dict(elem, resolve_pseudo_property, pseudo='first-letter') font = get_font_dict(elem, resolve_pseudo_property, pseudo='first-letter')
text = get_element_text(elem, resolve_property, resolve_pseudo_property, self.capitalize_pat, for_pseudo='first-letter') text = get_element_text(elem, resolve_property, resolve_pseudo_property, self.capitalize_pat, for_pseudo='first-letter')
m = self.first_letter_pat.search(text.lstrip()) m = self.first_letter_pat.search(text.lstrip())
@ -259,9 +258,8 @@ class StatsCollector:
update_usage_for_embed(font, chars) update_usage_for_embed(font, chars)
for rule in get_matching_rules(font_face_rules, font): for rule in get_matching_rules(font_face_rules, font):
self.font_stats[rule['src']] |= chars self.font_stats[rule['src']] |= chars
q = resolve_pseudo_property(elem, 'first-line', 'font-family', abort_on_missing=True) if resolve_pseudo_property(elem, 'first-line', 'font-family', check_if_pseudo_applies=True, check_ancestors=True):
if q is not None: font = get_font_dict(elem, partial(resolve_pseudo_property, check_ancestors=True), pseudo='first-line')
font = get_font_dict(elem, resolve_pseudo_property, pseudo='first-line')
text = get_element_text(elem, resolve_property, resolve_pseudo_property, self.capitalize_pat, for_pseudo='first-line') text = get_element_text(elem, resolve_property, resolve_pseudo_property, self.capitalize_pat, for_pseudo='first-line')
chars = frozenset(ord_string(text)) - exclude_chars chars = frozenset(ord_string(text)) - exclude_chars
update_usage_for_embed(font, chars) update_usage_for_embed(font, chars)

View File

@ -160,7 +160,6 @@ class CascadeTest(BaseTest):
v = 'url(%s)' % v v = 'url(%s)' % v
styles.append(f'{k} : {v};') styles.append(f'{k} : {v};')
styles.append('}\n') styles.append('}\n')
html = f'<html><head><link href="styles.css"></head><body>{html}</body></html>'
files['styles.css'] = embeds + '\n'.join(styles) files['styles.css'] = embeds + '\n'.join(styles)
c = VirtualContainer(files) c = VirtualContainer(files)
return StatsCollector(c, do_embed=True) return StatsCollector(c, do_embed=True)
@ -207,6 +206,9 @@ class CascadeTest(BaseTest):
s = get_stats('<p style="font-family: X; text-transform:uppercase">abc</p><b style="font-family: X; font-variant: small-caps">d\nef</b>') s = get_stats('<p style="font-family: X; text-transform:uppercase">abc</p><b style="font-family: X; font-variant: small-caps">d\nef</b>')
self.assertEqual(s.font_stats, {'XB.otf':set('defDEF'), 'X.otf':set('ABC')}) self.assertEqual(s.font_stats, {'XB.otf':set('defDEF'), 'X.otf':set('ABC')})
s = get_stats('<style>.fl::first-line { font-family: X }</style><p class="fl">abc<b>def</b></p>')
# Technically def should not be needed in X but that is hard to achieve
self.assertEqual(s.font_stats, {'XB.otf':set('def'), 'X.otf':set('abcdef')})
def test_remove_property_value(self): def test_remove_property_value(self):
style = parseStyle('background-image: url(b.png); background: black url(a.png) fixed') style = parseStyle('background-image: url(b.png); background: black url(a.png) fixed')