Dillo
Interrupted drawing

Describing the problem

Without interrupting drawing (which is described below), a widget can define the order in which its parts (background, non-widget content, child widgets, etc.) are drawn, but it must be drawn as a whole. There are situations when this is not possible.

Consider the following simple HTML document:

<head>
  <style>
    #sc-1 { position: relative; z-index: 1; background: #ffe0e0; }
    #fl-1 { float: right; background: #b0ffb0; }
    #sc-2 { position: relative; z-index: 1; background: #f0f0ff; }
  </style>
</head>
<body>
  <div id="sc-1">
    <div id="fl-1">
      Float, line 1/3<br/>
      Float, line 2/3<br/>
      Float, line 3/3
    </div>
    Stacking Context 1 
    <div id="sc-2">Stacking Context 2</div>
  </div>
</body>

The rendering will look like this:

dw-interrupted-drawing-1.png

Note the missing "Float, line 2/3" of element #fl-1, which is covered by element #sc-2.

As described in Handling Elements Out Of Flow, it has to be distinguished between the container hierarchy (equivalent to the hierarchy of dw::core::Widget.) and the the generator hierarchy. In the following diagram, the former is represented by solid lines, the latter by dotted lines:

dot_inline_dotgraph_3.png

The drawing order of the four elements (represented by widgets) is:

Since

  1. #sc-2 is a child of #sc-1, but
  2. #fl-1 is a child of the body, and
  3. a widget can only draw its descendants (not neccessary children, but drawing siblings is not allowed),

#sc-1 cannot be drawn as a whole; instead drawing is interrupted by #fl-1. This means:

  1. the background and text of #sc-1 is drawn;
  2. drawing of #sc-1 is interrupted by #fl-1 (see below for details),
  3. drawing of #sc-1 is continued, by drawing #sc-2.

The exact control flow is described in this sequence diagram:

dw-interrupted-drawing-2.png

When is drawing interrupted?

A widget out of flow is regarded as part of the stacking context (see Handling stacking contexts) of its generator (in the example above: #fl-1 is part of the stacking context stablished by #sc-1, not the one established by body). For this reason, a widget out of flow must, in some cases, drawn while the gerator is drawn, as an interruption. The exact rule:

A widget out of flow must be drawn as an interruption (while the generator* is drawn) if the stacking context of the generator (to which this widget belongs) is in front of the stacking context of the container (the parent widget).

See dw::oof::OOFAwareWidget::doesWidgetOOFInterruptDrawing.

How does interruption of drawing work?

When a widget detects that an other widget should be drawn as interruption (see above), it calls dw::core::Widget::drawInterruption, which

  1. draws the widget within another "context" (area and reference widget); for this the original drawing area (dw::core::DrawingContext::getToplevelArea) is used.
  2. Using dw::core::DrawingContext::addWidgetDrawnAsInterruption, and checking later with dw::core::DrawingContext::hasWidgetBeenDrawnAsInterruption prevents these widgets from being drawn twice.