mirror of
https://github.com/gryf/ebook-converter.git
synced 2026-02-21 17:25:55 +01:00
Initial import
This commit is contained in:
163
ebook_converter/tinycss/page3.py
Normal file
163
ebook_converter/tinycss/page3.py
Normal file
@@ -0,0 +1,163 @@
|
||||
# coding: utf8
|
||||
"""
|
||||
tinycss.page3
|
||||
------------------
|
||||
|
||||
Support for CSS 3 Paged Media syntax:
|
||||
http://dev.w3.org/csswg/css3-page/
|
||||
|
||||
Adds support for named page selectors and margin rules.
|
||||
|
||||
:copyright: (c) 2012 by Simon Sapin.
|
||||
:license: BSD, see LICENSE for more details.
|
||||
"""
|
||||
|
||||
from __future__ import unicode_literals, division
|
||||
from .css21 import CSS21Parser, ParseError
|
||||
|
||||
|
||||
class MarginRule(object):
|
||||
"""A parsed at-rule for margin box.
|
||||
|
||||
.. attribute:: at_keyword
|
||||
|
||||
One of the 16 following strings:
|
||||
|
||||
* ``@top-left-corner``
|
||||
* ``@top-left``
|
||||
* ``@top-center``
|
||||
* ``@top-right``
|
||||
* ``@top-right-corner``
|
||||
* ``@bottom-left-corner``
|
||||
* ``@bottom-left``
|
||||
* ``@bottom-center``
|
||||
* ``@bottom-right``
|
||||
* ``@bottom-right-corner``
|
||||
* ``@left-top``
|
||||
* ``@left-middle``
|
||||
* ``@left-bottom``
|
||||
* ``@right-top``
|
||||
* ``@right-middle``
|
||||
* ``@right-bottom``
|
||||
|
||||
.. attribute:: declarations
|
||||
|
||||
A list of :class:`~.css21.Declaration` objects.
|
||||
|
||||
.. attribute:: line
|
||||
|
||||
Source line where this was read.
|
||||
|
||||
.. attribute:: column
|
||||
|
||||
Source column where this was read.
|
||||
|
||||
"""
|
||||
|
||||
__slots__ = 'at_keyword', 'declarations', 'line', 'column'
|
||||
|
||||
def __init__(self, at_keyword, declarations, line, column):
|
||||
self.at_keyword = at_keyword
|
||||
self.declarations = declarations
|
||||
self.line = line
|
||||
self.column = column
|
||||
|
||||
|
||||
class CSSPage3Parser(CSS21Parser):
|
||||
"""Extend :class:`~.css21.CSS21Parser` for `CSS 3 Paged Media`_ syntax.
|
||||
|
||||
.. _CSS 3 Paged Media: http://dev.w3.org/csswg/css3-page/
|
||||
|
||||
Compared to CSS 2.1, the ``at_rules`` and ``selector`` attributes of
|
||||
:class:`~.css21.PageRule` objects are modified:
|
||||
|
||||
* ``at_rules`` is not always empty, it is a list of :class:`MarginRule`
|
||||
objects.
|
||||
|
||||
* ``selector``, instead of a single string, is a tuple of the page name
|
||||
and the pseudo class. Each of these may be a ``None`` or a string.
|
||||
|
||||
+--------------------------+------------------------+
|
||||
| CSS | Parsed selectors |
|
||||
+==========================+========================+
|
||||
| .. code-block:: css | .. code-block:: python |
|
||||
| | |
|
||||
| @page {} | (None, None) |
|
||||
| @page :first {} | (None, 'first') |
|
||||
| @page chapter {} | ('chapter', None) |
|
||||
| @page table:right {} | ('table', 'right') |
|
||||
+--------------------------+------------------------+
|
||||
|
||||
"""
|
||||
|
||||
PAGE_MARGIN_AT_KEYWORDS = (
|
||||
'@top-left-corner',
|
||||
'@top-left',
|
||||
'@top-center',
|
||||
'@top-right',
|
||||
'@top-right-corner',
|
||||
'@bottom-left-corner',
|
||||
'@bottom-left',
|
||||
'@bottom-center',
|
||||
'@bottom-right',
|
||||
'@bottom-right-corner',
|
||||
'@left-top',
|
||||
'@left-middle',
|
||||
'@left-bottom',
|
||||
'@right-top',
|
||||
'@right-middle',
|
||||
'@right-bottom',
|
||||
)
|
||||
|
||||
def __init__(self):
|
||||
super(CSSPage3Parser, self).__init__()
|
||||
for x in self.PAGE_MARGIN_AT_KEYWORDS:
|
||||
self.at_parsers[x] = self.parse_page_margin_rule
|
||||
|
||||
def parse_page_margin_rule(self, rule, previous_rules, errors, context):
|
||||
if context != '@page':
|
||||
raise ParseError(rule,
|
||||
'%s rule not allowed in %s' % (rule.at_keyword, context))
|
||||
if rule.head:
|
||||
raise ParseError(rule.head[0],
|
||||
'unexpected %s token in %s rule header'
|
||||
% (rule.head[0].type, rule.at_keyword))
|
||||
declarations, body_errors = self.parse_declaration_list(rule.body)
|
||||
errors.extend(body_errors)
|
||||
return MarginRule(rule.at_keyword, declarations,
|
||||
rule.line, rule.column)
|
||||
|
||||
def parse_page_selector(self, head):
|
||||
"""Parse an @page selector.
|
||||
|
||||
:param head:
|
||||
The ``head`` attribute of an unparsed :class:`AtRule`.
|
||||
:returns:
|
||||
A page selector. For CSS 2.1, this is 'first', 'left', 'right'
|
||||
or None. 'blank' is added by GCPM.
|
||||
:raises:
|
||||
:class`~parsing.ParseError` on invalid selectors
|
||||
|
||||
"""
|
||||
if not head:
|
||||
return (None, None), (0, 0, 0)
|
||||
if head[0].type == 'IDENT':
|
||||
name = head.pop(0).value
|
||||
while head and head[0].type == 'S':
|
||||
head.pop(0)
|
||||
if not head:
|
||||
return (name, None), (1, 0, 0)
|
||||
name_specificity = (1,)
|
||||
else:
|
||||
name = None
|
||||
name_specificity = (0,)
|
||||
if (len(head) == 2 and head[0].type == ':'
|
||||
and head[1].type == 'IDENT'):
|
||||
pseudo_class = head[1].value
|
||||
specificity = {
|
||||
'first': (1, 0), 'blank': (1, 0),
|
||||
'left': (0, 1), 'right': (0, 1),
|
||||
}.get(pseudo_class)
|
||||
if specificity:
|
||||
return (name, pseudo_class), (name_specificity + specificity)
|
||||
raise ParseError(head[0], 'invalid @page selector')
|
||||
Reference in New Issue
Block a user