Make media query handling a little more robust

This commit is contained in:
Kovid Goyal 2015-07-22 13:09:54 +05:30
parent 6a2f6c2ad4
commit e5cdc8f347

View File

@ -50,24 +50,46 @@ FONT_SIZE_NAMES = {
'xx-small', 'x-small', 'small', 'medium', 'large', 'x-large', 'xx-large' 'xx-small', 'x-small', 'small', 'medium', 'large', 'x-large', 'xx-large'
} }
ALL_MEDIA_TYPES = frozenset('all aural braille handheld print projection screen tty tv embossed amzn-mobi amzn-kf8'.split())
ALLOWED_MEDIA_TYPES = frozenset({'screen', 'all', 'aural', 'amzn-kf8'})
IGNORED_MEDIA_FEATURES = frozenset('width min-width max-width height min-height max-height device-width min-device-width max-device-width device-height min-device-height max-device-height aspect-ratio min-aspect-ratio max-aspect-ratio device-aspect-ratio min-device-aspect-ratio max-device-aspect-ratio color min-color max-color color-index min-color-index max-color-index monochrome min-monochrome max-monochrome resolution min-resolution max-resolution scan grid'.split()) # noqa IGNORED_MEDIA_FEATURES = frozenset('width min-width max-width height min-height max-height device-width min-device-width max-device-width device-height min-device-height max-device-height aspect-ratio min-aspect-ratio max-aspect-ratio device-aspect-ratio min-device-aspect-ratio max-device-aspect-ratio color min-color max-color color-index min-color-index max-color-index monochrome min-monochrome max-monochrome resolution min-resolution max-resolution scan grid'.split()) # noqa
def media_ok(raw): def media_ok(raw):
if not raw: if not raw:
return True return True
if raw == 'amzn-mobi': if raw == 'amzn-mobi': # Optimization for the common case
return False return False
try:
mq = CSSMedia3Parser().parse_stylesheet(u'@media %s {}' % raw).rules[0].media[0] def query_ok(mq):
if mq.media_type not in {'screen', 'all', 'aural'}: matched = True
return False if mq.media_type not in ALLOWED_MEDIA_TYPES:
matched = False
# Media queries that test for device specific features always fail
for media_feature, expr in mq.expressions: for media_feature, expr in mq.expressions:
if media_feature in IGNORED_MEDIA_FEATURES: if media_feature in IGNORED_MEDIA_FEATURES:
return False matched = False
return mq.negated ^ matched
try:
for mq in CSSMedia3Parser().parse_stylesheet(u'@media %s {}' % raw).rules[0].media:
if query_ok(mq):
return True
return False
except Exception: except Exception:
pass pass
return True return True
def test_media_ok():
assert media_ok(None)
assert media_ok('')
assert not media_ok('amzn-mobi')
assert media_ok('amzn-kf8')
assert media_ok('screen')
assert not media_ok('not screen')
assert not media_ok('(device-width:10px)')
assert media_ok('screen, (device-width:10px)')
assert not media_ok('screen and (device-width:10px)')
class Stylizer(object): class Stylizer(object):
STYLESHEETS = WeakKeyDictionary() STYLESHEETS = WeakKeyDictionary()
@ -108,7 +130,7 @@ class Stylizer(object):
self.font_face_rules = [] self.font_face_rules = []
for elem in style_tags: for elem in style_tags:
if (elem.tag == XHTML('style') and if (elem.tag == XHTML('style') and
elem.get('type', CSS_MIME) in OEB_STYLES): elem.get('type', CSS_MIME) in OEB_STYLES and media_ok(elem.get('media'))):
text = elem.text if elem.text else u'' text = elem.text if elem.text else u''
for x in elem: for x in elem:
t = getattr(x, 'text', None) t = getattr(x, 'text', None)
@ -145,12 +167,11 @@ class Stylizer(object):
replaceUrls(stylesheet, item.abshref, replaceUrls(stylesheet, item.abshref,
ignoreImportRules=True) ignoreImportRules=True)
stylesheets.append(stylesheet) stylesheets.append(stylesheet)
elif elem.tag == XHTML('link') and elem.get('href') \ elif (elem.tag == XHTML('link') and elem.get('href') and
and elem.get('rel', 'stylesheet').lower() == 'stylesheet' \ elem.get('rel', 'stylesheet').lower() == 'stylesheet' and
and elem.get('type', CSS_MIME).lower() in OEB_STYLES: elem.get('type', CSS_MIME).lower() in OEB_STYLES and
media = elem.get('media', '') media_ok(elem.get('media'))
if not media_ok(media): ):
continue
href = urlnormalize(elem.attrib['href']) href = urlnormalize(elem.attrib['href'])
path = item.abshref(href) path = item.abshref(href)
sitem = oeb.manifest.hrefs.get(path, None) sitem = oeb.manifest.hrefs.get(path, None)