示例#1
0
    def layout_table_cell(self, lc):
        """Lay out a table cell element and its descendants."""

        # we're basically doing block layout here, but within a fake context
        # tailored to our place in the table

        align = self.get_style("text-align",
                               None,
                               Value('IDENT', 'left'),
                               inherit=True)

        # fake dimensions for this table cell

        tlc = lc.get_table_context()

        d = lc.containing_block_dim

        fake_dim = Dimensions()
        fake_dim.content.x = d.content.x + tlc.line_width
        fake_dim.content.y = d.content.y + lc.height

        w = tlc.table_colw[tlc.table_coli] * tlc.table_colf

        fake_dim.content.width = w
        fake_dim.content.height = 0

        #print "layout_table_cell: fake_dim.content: %s" % fake_dim.content

        fake_lc = LayoutContext(lc, fake_dim, align.to_str())

        self.layout_block(fake_lc)

        tlc.line_width += w
        tlc.table_coli += 1
示例#2
0
    def calculate_block_position(self, lc):
        """Finish calculating the block's edge sizes, and position it within its containing block."""
        """http://www.w3.org/TR/CSS2/visudet.html#normal-block"""
        """Sets the vertical margin/padding/border dimensions, and the `x`, `y` values."""

        #print "calculate_block_position: %s" % self

        d = self.dimensions

        # margin, border, and padding have initial value 0.
        zero = Value('DIMENSION', 0.0, 'px')

        # If margin-top or margin-bottom is `auto`, the used value is zero.
        d.margin.top = self.get_style("margin-top", "margin", zero).to_px()
        d.margin.bottom = self.get_style("margin-bottom", "margin",
                                         zero).to_px()

        d.border.top = self.get_style("border-top-width", "border-width",
                                      zero).to_px()
        d.border.bottom = self.get_style("border-bottom-width", "border-width",
                                         zero).to_px()

        d.padding.top = self.get_style("padding-top", "padding", zero).to_px()
        d.padding.bottom = self.get_style("padding-bottom", "padding",
                                          zero).to_px()

        d.content.x = lc.containing_block_dim.content.x + d.margin.left + d.border.left + d.padding.left

        # Position the box below all the previous boxes in the container.
        d.content.y = lc.height + lc.containing_block_dim.content.y + d.margin.top + d.border.top + d.padding.top
示例#3
0
    def layout_block_children(self, lc):

        align = self.get_style("text-align",
                               None,
                               Value('IDENT', 'left'),
                               inherit=True)

        clc = LayoutContext(lc, self.dimensions, align.to_str())
        for child in self.children:
            child.layout(clc)

        # finish + align last line
        clc.line_wrap()

        return clc
示例#4
0
    def layout_inline_children(self, lc):
        align = self.get_style("text-align",
                               None,
                               Value('IDENT', 'left'),
                               inherit=True)

        clc = LayoutContext(lc, self.dimensions, align.to_str())
        for child in self.children:
            child.layout(clc)

        # finish + align last line
        clc.line_wrap()

        if clc.height > self.dimensions.content.height:
            self.dimensions.content.height = clc.height
示例#5
0
    def layout_table(self, lc):
        """ Very simple table layout support at this point. """

        d = self.dimensions
        align = self.get_style("text-align",
                               None,
                               Value('IDENT', 'left'),
                               inherit=True)

        #
        # ask children about their widths to determine column widths
        #
        lc.table_colw = []
        for tpart in self.children:
            #print "layout_table:   tpart=%s" % tpart
            for tr in tpart.children:
                #print "layout_table:      tr=%s" % tr
                col_i = 0
                for td in tr.children:
                    #print "layout_table:         td=%s" % td
                    if len(lc.table_colw) <= col_i:
                        lc.table_colw.append(0.0)

                    td.calculate_inline_width_height()

                    mb = td.dimensions.margin_box()

                    if mb.width > lc.table_colw[col_i]:
                        lc.table_colw[col_i] = mb.width
                    col_i += 1

        lc.table_colw_sum = reduce(lambda x, y: x + y, lc.table_colw, 0.0)
        #print "layout_table: colw=%s sum=%f" % (repr(lc.table_colw), lc.table_colw_sum)

        #
        # continue with regular block layout for now
        # (tds will use lc table info further down in the tree)
        #

        self.layout_block(lc)
示例#6
0
    def calculate_block_width(self, lc):
        """Calculate the width of a block-level non-replaced element in normal flow."""
        """http://www.w3.org/TR/CSS2/visudet.html#blockwidth"""
        """Sets the horizontal margin/padding/border dimensions, and the `width`."""

        #print "calculate_block_width: %s" % (self)

        # `width` has initial value `auto`.
        auto = Value('IDENT', 'auto')
        width = self.get_style('width', None, auto)

        # margin, border, and padding have initial value 0.

        zero = Value('DIMENSION', 0.0, 'px')

        margin_left = self.get_style("margin-left", "margin", zero)
        margin_right = self.get_style("margin-right", "margin", zero)

        border_left = self.get_style("border-left-width", "border-width", zero)
        border_right = self.get_style("border-right-width", "border-width",
                                      zero)

        padding_left = self.get_style("padding-left", "padding", zero)
        padding_right = self.get_style("padding-right", "padding", zero)

        total = reduce(
            lambda x, y: x + y,
            map(lambda x: 0.0 if x.is_auto() else x.to_px(), [
                margin_left, margin_right, border_left, border_right,
                padding_left, padding_right, width
            ]))

        #print "   margin: %s, %s;\n   border: %s, %s;\n   padding: %s, %s;\n   total: %s" % (margin_left, margin_right, border_left, border_right, padding_left, padding_right, total)

        # If width is not auto and the total is wider than the container, treat auto margins as 0.
        if not width.is_auto(
        ) and total > lc.containing_block_dim.content.width:
            if margin_left.is_auto():
                margin_left = zero

            if margin_right.is_auto():
                margin_right = zero

        # Adjust used values so that the above sum equals `lc.containing_block_dim.width`.
        # Each arm of the `match` should increase the total width by exactly `underflow`,
        # and afterward all values should be absolute lengths in px.
        underflow = lc.containing_block_dim.content.width - total

        #print "   underflow: %f" % underflow

        # If the values are overconstrained, calculate margin_right.
        if not width.is_auto() and not margin_left.is_auto(
        ) and not margin_right.is_auto():
            margin_right = Value.length(margin_right.to_px() + underflow, 'px')

        # If exactly one size is auto, its used value follows from the equality.
        elif not width.is_auto() and not margin_left.is_auto(
        ) and margin_right.is_auto():
            margin_right = Value.length(underflow, 'px')
        elif not width.is_auto() and margin_left.is_auto(
        ) and not margin_right.is_auto():
            margin_right = Value.length(underflow, 'px')

        # If width is set to auto, any other auto values become 0.
        elif width.is_auto():
            if margin_left.is_auto():
                margin_left = Value.length(0.0, 'px')
            if margin_right.is_auto():
                margin_right = Value.length(0.0, 'px')

            if underflow >= 0.0:
                # Expand width to fill the underflow.
                width = Value.length(underflow, 'px')
            else:
                # Width can't be negative. Adjust the right margin instead.
                width = Value.length(0.0, 'px')
                margin_right = Value.length(margin_right.to_px() + underflow,
                                            'px')

        # If margin-left and margin-right are both auto, their used values are equal.
        elif not width.is_auto() and margin_left.is_auto(
        ) and margin_right.is_auto():
            margin_left = Value.length(underflow / 2.0, 'px')
            margin_right = Value.length(underflow / 2.0, 'px')

        d = self.dimensions
        d.content.width = width.to_px()

        d.padding.left = padding_left.to_px()
        d.padding.right = padding_right.to_px()

        d.border.left = border_left.to_px()
        d.border.right = border_right.to_px()

        d.margin.left = margin_left.to_px()
        d.margin.right = margin_right.to_px()
示例#7
0
    def calculate_inline_width_height(self):
        #print "calculate_inline_width_height: %s" % (self)

        # margin, border, and padding have initial value 0.

        margin_left = self.get_style("margin-left", "margin", zero)
        margin_right = self.get_style("margin-right", "margin", zero)
        margin_top = self.get_style("margin-top", "margin", zero)
        margin_bottom = self.get_style("margin-bottom", "margin", zero)

        border_left = self.get_style("border-left-width", "border-width", zero)
        border_right = self.get_style("border-right-width", "border-width",
                                      zero)
        border_top = self.get_style("border-top-width", "border-width", zero)
        border_bottom = self.get_style("border-bottom-width", "border-width",
                                       zero)

        padding_left = self.get_style("padding-left", "padding", zero)
        padding_right = self.get_style("padding-right", "padding", zero)
        padding_top = self.get_style("padding-top", "padding", zero)
        padding_bottom = self.get_style("padding-bottom", "padding", zero)

        # calculate text size

        font_family = self.get_style("font-family",
                                     None,
                                     "Monospace",
                                     inherit=True)
        font_size = self.get_style("font-size", None, 16, inherit=True)
        if self.text is not None:
            xtents = self.html.text_extents(self.html.user_data,
                                            font_family.to_str(),
                                            font_size.to_px(), self.text)
            width = xtents[4]
            xtents = self.html.font_extents(self.html.user_data,
                                            font_family.to_str(),
                                            font_size.to_px())
            height = xtents[2]
        else:
            width = 0
            height = 0

        width = self.get_style("width", "width", Value('DIMENSION', width,
                                                       'px')).to_px()

        # make room for children, if any

        for child in self.children:
            if child.box_type == 'img':
                child.calculate_image_width_height()
            else:
                child.calculate_inline_width_height()

            cb = child.dimensions.margin_box()

            if cb.width > width:
                width = cb.width
            if cb.height > height:
                height = cb.height

        d = self.dimensions
        d.content.width = width
        d.content.height = height

        d.padding.left = padding_left.to_px()
        d.padding.right = padding_right.to_px()
        d.padding.top = padding_top.to_px()
        d.padding.bottom = padding_bottom.to_px()

        d.border.left = border_left.to_px()
        d.border.right = border_right.to_px()
        d.border.top = border_top.to_px()
        d.border.bottom = border_bottom.to_px()

        d.margin.left = margin_left.to_px()
        d.margin.right = margin_right.to_px()
        d.margin.top = margin_top.to_px()
        d.margin.bottom = margin_bottom.to_px()
示例#8
0
    def __init__(self, html, css, width, load_resourcefn, text_extents, font_extents, user_data):

        self.text_extents    = text_extents
        self.font_extents    = font_extents
        self.load_resourcefn = load_resourcefn
        self.user_data       = user_data

        if VERBOSE:
            start = time.clock()
            end   = time.clock()
            print "robinson: %8.3fs lxml parsing..." % (end-start)

            pr = cProfile.Profile()

        root = etree.fromstring(html)
        document = etree.ElementTree(root)

        if VERBOSE:
            end   = time.clock()

            print repr(root), root.__class__
            print document, repr(document), document.__class__
            print etree.tostring(document.getroot())

            print "robinson: %8.3fs tinycss.css21.CSS21Parser()..." % (end-start)

        cssparser = tinycss.css21.CSS21Parser()

        stylesheet = cssparser.parse_stylesheet(css)
        
        if VERBOSE:
            end   = time.clock()
            print "robinson: %8.3fs style mapping..." % (end-start)

        style_map = {}

        sel_to_xpath = cssselect.xpath.HTMLTranslator().selector_to_xpath
        for rule in stylesheet.rules:
            if not isinstance (rule, tinycss.css21.RuleSet):
                continue

            sel_css = rule.selector.as_css()
            sels    = cssselect.parse (sel_css)

            #print "CSS Ruleset: %s" % (rule.selector.as_css())

            for sel in sels:
                speci = sel.specificity()
                prio  = speci2prio (speci)
                #print "   selector: %s, specificity: %s (%06d)" % (repr(sel), sel.specificity(), prio)

                xpath = sel_to_xpath (sel)
                #print "   xpath: %s" % repr(xpath)

                for item in document.xpath(xpath):
                    #print "     matched item: %s" % repr(item.tag)

                    if not item in style_map:
                        style_map[item] = {}

                    for decl in rule.declarations:
                        #print "       declaration: %s: %s" % (decl.name, decl.value)

                        if not decl.name in style_map[item]:
                            style_map[item][decl.name] = (prio, Value.from_token(decl.value))
                        else:
                            if prio > style_map[item][decl.name][0]:
                                style_map[item][decl.name] = (prio, Value.from_token(decl.value))
         
        #print "Style map done."
        #print repr(style_map)

        if VERBOSE:
            end   = time.clock()
            print "robinson: %8.3fs building layout tree..." % (end-start)
            pr.enable()

        viewport = Dimensions ()
        viewport.content.width  = width
        self.ltree = self._layout_tree (document.getroot(), style_map, viewport)

        if VERBOSE:
            end   = time.clock()
            print "robinson: %8.3fs __init__ done." % (end-start)
示例#9
0
文件: layout.py 项目: gooofy/robinson
    def calculate_block_width(self, lc):
        """Calculate the width of a block-level non-replaced element in normal flow."""     
        """http://www.w3.org/TR/CSS2/visudet.html#blockwidth"""
        """Sets the horizontal margin/padding/border dimensions, and the `width`."""

        #print "calculate_block_width: %s" % (self)

        # `width` has initial value `auto`.
        auto = Value('IDENT', 'auto')
        width = self.get_style ('width', None, auto)

        # margin, border, and padding have initial value 0.

        zero = Value ('DIMENSION', 0.0, 'px')

        margin_left = self.get_style("margin-left", "margin", zero)
        margin_right = self.get_style("margin-right", "margin", zero)

        border_left = self.get_style("border-left-width", "border-width", zero)
        border_right = self.get_style("border-right-width", "border-width", zero)

        padding_left = self.get_style("padding-left", "padding", zero)
        padding_right = self.get_style("padding-right", "padding", zero)
 
        total = reduce(lambda x, y: x+y, 
                           map(lambda x: 0.0 if x.is_auto() else x.to_px(), 
                               [margin_left, margin_right, border_left, border_right,
                                padding_left, padding_right, width]))

        #print "   margin: %s, %s;\n   border: %s, %s;\n   padding: %s, %s;\n   total: %s" % (margin_left, margin_right, border_left, border_right, padding_left, padding_right, total)
 
        # If width is not auto and the total is wider than the container, treat auto margins as 0.
        if not width.is_auto() and total > lc.containing_block_dim.content.width:
            if margin_left.is_auto():
                margin_left = zero
            
            if margin_right.is_auto():
                margin_right = zero
            

        # Adjust used values so that the above sum equals `lc.containing_block_dim.width`.
        # Each arm of the `match` should increase the total width by exactly `underflow`,
        # and afterward all values should be absolute lengths in px.
        underflow = lc.containing_block_dim.content.width - total

        #print "   underflow: %f" % underflow

        # If the values are overconstrained, calculate margin_right.
        if not width.is_auto() and not margin_left.is_auto() and not margin_right.is_auto():
            margin_right = Value.length(margin_right.to_px() + underflow, 'px')

        # If exactly one size is auto, its used value follows from the equality.
        elif not width.is_auto() and not margin_left.is_auto() and margin_right.is_auto():
            margin_right = Value.length(underflow, 'px')
        elif not width.is_auto() and margin_left.is_auto() and not margin_right.is_auto():
            margin_right = Value.length(underflow, 'px')

        # If width is set to auto, any other auto values become 0.
        elif width.is_auto() :
            if margin_left.is_auto():
                margin_left = Value.length(0.0, 'px')
            if margin_right.is_auto():
                margin_right = Value.length(0.0, 'px')

            if underflow >= 0.0:
                # Expand width to fill the underflow.
                width = Value.length(underflow, 'px')
            else:
                # Width can't be negative. Adjust the right margin instead.
                width = Value.length(0.0, 'px')
                margin_right = Value.length(margin_right.to_px() + underflow, 'px')

        # If margin-left and margin-right are both auto, their used values are equal.
        elif not width.is_auto() and margin_left.is_auto() and margin_right.is_auto():
            margin_left = Value.length(underflow / 2.0, 'px');
            margin_right = Value.length(underflow / 2.0, 'px');


        d = self.dimensions
        d.content.width = width.to_px()

        d.padding.left = padding_left.to_px()
        d.padding.right = padding_right.to_px()

        d.border.left = border_left.to_px()
        d.border.right = border_right.to_px()

        d.margin.left = margin_left.to_px()
        d.margin.right = margin_right.to_px()
示例#10
0
    def __init__(self, html, css, width, load_resourcefn, text_extents,
                 font_extents, user_data):

        self.text_extents = text_extents
        self.font_extents = font_extents
        self.load_resourcefn = load_resourcefn
        self.user_data = user_data

        if VERBOSE:
            start = time.clock()
            end = time.clock()
            print("robinson: %8.3fs lxml parsing..." % (end - start))

            pr = cProfile.Profile()

        root = etree.fromstring(html)
        document = etree.ElementTree(root)

        if VERBOSE:
            end = time.clock()

            print(repr(root), root.__class__)
            print(document, repr(document), document.__class__)
            print(etree.tostring(document.getroot()))

            print("robinson: %8.3fs tinycss.css21.CSS21Parser()..." %
                  (end - start))

        cssparser = tinycss.css21.CSS21Parser()

        stylesheet = cssparser.parse_stylesheet(css)

        if VERBOSE:
            end = time.clock()
            print("robinson: %8.3fs style mapping..." % (end - start))

        style_map = {}

        sel_to_xpath = cssselect.xpath.HTMLTranslator().selector_to_xpath
        for rule in stylesheet.rules:
            if not isinstance(rule, tinycss.css21.RuleSet):
                continue

            sel_css = rule.selector.as_css()
            sels = cssselect.parse(sel_css)

            #print "CSS Ruleset: %s" % (rule.selector.as_css())

            for sel in sels:
                speci = sel.specificity()
                prio = speci2prio(speci)
                #print "   selector: %s, specificity: %s (%06d)" % (repr(sel), sel.specificity(), prio)

                xpath = sel_to_xpath(sel)
                #print "   xpath: %s" % repr(xpath)

                for item in document.xpath(xpath):
                    #print "     matched item: %s" % repr(item.tag)

                    if not item in style_map:
                        style_map[item] = {}

                    for decl in rule.declarations:
                        #print "       declaration: %s: %s" % (decl.name, decl.value)

                        if not decl.name in style_map[item]:
                            style_map[item][decl.name] = (prio,
                                                          Value.from_token(
                                                              decl.value))
                        else:
                            if prio > style_map[item][decl.name][0]:
                                style_map[item][decl.name] = (prio,
                                                              Value.from_token(
                                                                  decl.value))

        #print "Style map done."
        #print repr(style_map)

        if VERBOSE:
            end = time.clock()
            print("robinson: %8.3fs building layout tree..." % (end - start))
            pr.enable()

        viewport = Dimensions()
        viewport.content.width = width
        self.ltree = self._layout_tree(document.getroot(), style_map, viewport)

        if VERBOSE:
            end = time.clock()
            print("robinson: %8.3fs __init__ done." % (end - start))