Permalink
Browse files

Fetch background images early

This removes the need to have a reference to the image cache
in draw.py
  • Loading branch information...
SimonSapin committed Sep 12, 2012
1 parent 43bccc7 commit 463a33c1af068388bf3eda8b8cebc321743d336f
@@ -24,6 +24,7 @@
'background_attachment': 'scroll',
'background_color': COLOR_KEYWORDS['transparent'],
'background_image': 'none',
+ '_fetched_background_image': None, # internal, image cache
'background_position': (Dimension(0, '%'), Dimension(0, '%')),
'background_repeat': 'repeat',
'background_clip': 'border-box', # CSS3
@@ -262,4 +263,4 @@
BACKGROUND_INITIAL = dict(
(name, value) for name, value in INITIAL_VALUES.items()
- if name.startswith('background'))
+ if 'background' in name)
View
@@ -50,8 +50,7 @@ def render_pages(self):
def draw_page(self, page, context):
"""Draw page on context at scale cairo device units per CSS pixel."""
- return draw.draw_page(page, context, self.enable_hinting,
- self.get_image_from_uri)
+ return draw.draw_page(page, context, self.enable_hinting)
def get_png_surfaces(self, resolution=None):
"""Yield (width, height, image_surface) tuples, one for each page."""
View
@@ -51,39 +51,31 @@ def lighten(color, offset):
color.alpha)
-def draw_page(page, context, enable_hinting, get_image_from_uri):
+def draw_page(page, context, enable_hinting):
"""Draw the given PageBox."""
stacking_context = StackingContext.from_page(page)
draw_box_background(
- context, stacking_context.page, stacking_context.box, enable_hinting,
- get_image_from_uri)
- draw_canvas_background(context, page, enable_hinting, get_image_from_uri)
+ context, stacking_context.page, stacking_context.box, enable_hinting)
+ draw_canvas_background(context, page, enable_hinting)
draw_border(context, page, enable_hinting)
- draw_stacking_context(context, stacking_context, enable_hinting,
- get_image_from_uri)
+ draw_stacking_context(context, stacking_context, enable_hinting)
-def draw_box_background_and_border(context, page, box, enable_hinting,
- get_image_from_uri):
- draw_box_background(context, page, box, enable_hinting, get_image_from_uri)
+def draw_box_background_and_border(context, page, box, enable_hinting):
+ draw_box_background(context, page, box, enable_hinting)
if not isinstance(box, boxes.TableBox):
draw_border(context, box, enable_hinting)
else:
for column_group in box.column_groups:
- draw_box_background(context, page, column_group, enable_hinting,
- get_image_from_uri)
+ draw_box_background(context, page, column_group, enable_hinting)
for column in column_group.children:
- draw_box_background(context, page, column, enable_hinting,
- get_image_from_uri)
+ draw_box_background(context, page, column, enable_hinting)
for row_group in box.children:
- draw_box_background(context, page, row_group, enable_hinting,
- get_image_from_uri)
+ draw_box_background(context, page, row_group, enable_hinting)
for row in row_group.children:
- draw_box_background(context, page, row, enable_hinting,
- get_image_from_uri)
+ draw_box_background(context, page, row, enable_hinting)
for cell in row.children:
- draw_box_background(context, page, cell, enable_hinting,
- get_image_from_uri)
+ draw_box_background(context, page, cell, enable_hinting)
if box.style.border_collapse == 'separate':
draw_border(context, box, enable_hinting)
for row_group in box.children:
@@ -94,8 +86,7 @@ def draw_box_background_and_border(context, page, box, enable_hinting,
draw_collapsed_borders(context, box, enable_hinting)
-def draw_stacking_context(context, stacking_context, enable_hinting,
- get_image_from_uri):
+def draw_stacking_context(context, stacking_context, enable_hinting):
"""Draw a ``stacking_context`` on ``context``."""
# See http://www.w3.org/TR/CSS2/zindex.html
with stacked(context):
@@ -133,38 +124,32 @@ def draw_stacking_context(context, stacking_context, enable_hinting,
boxes.InlineBlockBox)):
# The canvas background was removed by set_canvas_background
draw_box_background_and_border(
- context, stacking_context.page, box, enable_hinting,
- get_image_from_uri)
+ context, stacking_context.page, box, enable_hinting)
# Point 3
for child_context in stacking_context.negative_z_contexts:
- draw_stacking_context(context, child_context, enable_hinting,
- get_image_from_uri)
+ draw_stacking_context(context, child_context, enable_hinting)
# Point 4
for block in stacking_context.block_level_boxes:
draw_box_background_and_border(
- context, stacking_context.page, block, enable_hinting,
- get_image_from_uri)
+ context, stacking_context.page, block, enable_hinting)
# Point 5
for child_context in stacking_context.float_contexts:
- draw_stacking_context(context, child_context, enable_hinting,
- get_image_from_uri)
+ draw_stacking_context(context, child_context, enable_hinting)
# Point 6
if isinstance(box, boxes.InlineBox):
draw_inline_level(
- context, stacking_context.page, box,
- enable_hinting, get_image_from_uri)
+ context, stacking_context.page, box, enable_hinting)
# Point 7
for block in [box] + stacking_context.blocks_and_cells:
marker_box = getattr(block, 'outside_list_marker', None)
if marker_box:
draw_inline_level(
- context, stacking_context.page, marker_box,
- enable_hinting, get_image_from_uri)
+ context, stacking_context.page, marker_box, enable_hinting)
if isinstance(block, boxes.ReplacedBox):
draw_replacedbox(context, block)
@@ -174,17 +159,15 @@ def draw_stacking_context(context, stacking_context, enable_hinting,
# TODO: draw inline tables
draw_inline_level(
context, stacking_context.page, child,
- enable_hinting, get_image_from_uri)
+ enable_hinting)
# Point 8
for child_context in stacking_context.zero_z_contexts:
- draw_stacking_context(context, child_context, enable_hinting,
- get_image_from_uri)
+ draw_stacking_context(context, child_context, enable_hinting)
# Point 9
for child_context in stacking_context.positive_z_contexts:
- draw_stacking_context(context, child_context, enable_hinting,
- get_image_from_uri)
+ draw_stacking_context(context, child_context, enable_hinting)
# Point 10
draw_outlines(context, box, enable_hinting)
@@ -227,7 +210,7 @@ def background_positioning_area(page, box, style):
return box_rectangle(box, box.style.background_origin)
-def draw_canvas_background(context, page, enable_hinting, get_image_from_uri):
+def draw_canvas_background(context, page, enable_hinting):
if not page.children or isinstance(page.children[0], boxes.MarginBox):
# Skip the canvas background on content-empty pages
# TODO: remove this when content empty pages still get boxes
@@ -238,12 +221,10 @@ def draw_canvas_background(context, page, enable_hinting, get_image_from_uri):
draw_background(context, style,
painting_area=box_rectangle(page, 'padding-box'),
positioning_area=background_positioning_area(page, root_box, style),
- enable_hinting=enable_hinting,
- get_image_from_uri=get_image_from_uri)
+ enable_hinting=enable_hinting)
-def draw_box_background(context, page, box, enable_hinting,
- get_image_from_uri):
+def draw_box_background(context, page, box, enable_hinting):
"""Draw the box background color and image to a ``cairo.Context``."""
if box.style.visibility == 'hidden':
return
@@ -254,8 +235,7 @@ def draw_box_background(context, page, box, enable_hinting,
draw_background(
context, box.style, painting_area,
positioning_area=background_positioning_area(page, box, box.style),
- enable_hinting=enable_hinting,
- get_image_from_uri=get_image_from_uri)
+ enable_hinting=enable_hinting)
def percentage(value, refer_to):
@@ -268,14 +248,10 @@ def percentage(value, refer_to):
def draw_background(context, style, painting_area, positioning_area,
- enable_hinting, get_image_from_uri):
+ enable_hinting):
"""Draw the background color and image to a ``cairo.Context``."""
bg_color = style.background_color
- bg_image = style.background_image
- if bg_image == 'none':
- image = None
- else:
- image = get_image_from_uri(bg_image)
+ image = style._fetched_background_image
if bg_color.alpha == 0 and image is None:
# No background.
return
@@ -713,23 +689,20 @@ def draw_replacedbox(context, box):
box.replacement = 'Removed to work around cairo’s behavior'
-def draw_inline_level(context, page, box, enable_hinting, get_image_from_uri):
+def draw_inline_level(context, page, box, enable_hinting):
if isinstance(box, StackingContext):
stacking_context = box
assert isinstance(stacking_context.box, boxes.InlineBlockBox)
- draw_stacking_context(context, stacking_context, enable_hinting,
- get_image_from_uri)
+ draw_stacking_context(context, stacking_context, enable_hinting)
else:
- draw_box_background(
- context, page, box, enable_hinting, get_image_from_uri)
+ draw_box_background(context, page, box, enable_hinting)
draw_border(context, box, enable_hinting)
if isinstance(box, (boxes.InlineBox, boxes.LineBox)):
for child in box.children:
if isinstance(child, boxes.TextBox):
draw_text(context, child, enable_hinting)
else:
- draw_inline_level(context, page, child, enable_hinting,
- get_image_from_uri)
+ draw_inline_level(context, page, child, enable_hinting)
elif isinstance(box, boxes.InlineReplacedBox):
draw_replacedbox(context, box)
else:
@@ -61,7 +61,7 @@ def build_formatting_structure(element_tree, style_for, get_image_from_uri):
return box
-def make_box(element_tag, sourceline, style, content):
+def make_box(element_tag, sourceline, style, content, get_image_from_uri):
if (style.display in ('table', 'inline-table')
and style.border_collapse == 'collapse'):
# Padding do not apply
@@ -72,6 +72,10 @@ def make_box(element_tag, sourceline, style, content):
for side in ['top', 'bottom', 'left', 'right']:
style['margin_' + side] = ZERO_PIXELS
+ # Do this early so that draw.py does not need a reference to the cache.
+ style._fetched_background_image = (
+ get_image_from_uri(style.background_image)
+ if style.background_image != 'none' else None)
return BOX_TYPE_FROM_DISPLAY[style.display](element_tag, sourceline,
style, content)
@@ -112,7 +116,8 @@ def element_to_box(element, style_for, get_image_from_uri, state=None):
if display == 'none':
return []
- box = make_box(element.tag, element.sourceline, style, [])
+ box = make_box(element.tag, element.sourceline, style, [],
+ get_image_from_uri)
if state is None:
# use a list to have a shared mutable object
@@ -177,7 +182,8 @@ def pseudo_to_box(element, pseudo_type, state, style_for, get_image_from_uri):
return
box = make_box(
- '%s:%s' % (element.tag, pseudo_type), element.sourceline, style, [])
+ '%s:%s' % (element.tag, pseudo_type), element.sourceline, style, [],
+ get_image_from_uri)
quote_depth, counter_values, _counter_scopes = state
update_counters(state, style)
@@ -287,6 +287,10 @@ def make_box(at_keyword, containing_block):
style = context.style_for(page.page_type, at_keyword)
if style is None:
style = page.style.inherit_from()
+ # Do this early so that draw.py does not need a reference to the cache.
+ style._fetched_background_image = (
+ get_image_from_uri(style.background_image)
+ if style.background_image != 'none' else None)
box = boxes.MarginBox(at_keyword, style)
# Empty boxes should not be generated, but they may be needed for
# the layout of their neighbors.
@@ -470,6 +474,10 @@ def make_page(context, root_box, page_type, resume_at, content_empty):
style = context.style_for(page_type)
# Propagated from the root or <body>.
style.overflow = root_box.viewport_overflow
+ # Do this early so that draw.py does not need a reference to the cache.
+ style._fetched_background_image = (
+ get_image_from_uri(style.background_image)
+ if style.background_image != 'none' else None)
page = boxes.PageBox(page_type, style)
device_size = page.style.size

0 comments on commit 463a33c

Please sign in to comment.