Add more Skia pipeline unit tests.
Add more Skia pipeline unit tests and fix an issue
in backdrop/content bounds clip logic.
Test: built and run angler-eng and HWUI unit tests.
Change-Id: Ie41f80ff7ce9802a4d76e8b14f1695dbc9771a2b
diff --git a/libs/hwui/pipeline/skia/SkiaPipeline.cpp b/libs/hwui/pipeline/skia/SkiaPipeline.cpp
index d77aa48..6606b02 100644
--- a/libs/hwui/pipeline/skia/SkiaPipeline.cpp
+++ b/libs/hwui/pipeline/skia/SkiaPipeline.cpp
@@ -221,6 +221,14 @@
canvas->flush();
}
+namespace {
+static Rect nodeBounds(RenderNode& node) {
+ auto& props = node.properties();
+ return Rect(props.getLeft(), props.getTop(),
+ props.getRight(), props.getBottom());
+}
+}
+
void SkiaPipeline::renderFrameImpl(const LayerUpdateQueue& layers, const SkRect& clip,
const std::vector<sp<RenderNode>>& nodes, bool opaque, const Rect &contentDrawBounds,
SkCanvas* canvas) {
@@ -231,57 +239,85 @@
canvas->clear(SK_ColorTRANSPARENT);
}
- // If there are multiple render nodes, they are laid out as follows:
- // #0 - backdrop (content + caption)
- // #1 - content (positioned at (0,0) and clipped to - its bounds mContentDrawBounds)
- // #2 - additional overlay nodes
- // Usually the backdrop cannot be seen since it will be entirely covered by the content. While
- // resizing however it might become partially visible. The following render loop will crop the
- // backdrop against the content and draw the remaining part of it. It will then draw the content
- // cropped to the backdrop (since that indicates a shrinking of the window).
- //
- // Additional nodes will be drawn on top with no particular clipping semantics.
+ if (1 == nodes.size()) {
+ if (!nodes[0]->nothingToDraw()) {
+ SkAutoCanvasRestore acr(canvas, true);
+ RenderNodeDrawable root(nodes[0].get(), canvas);
+ root.draw(canvas);
+ }
+ } else if (0 == nodes.size()) {
+ //nothing to draw
+ } else {
+ // It there are multiple render nodes, they are laid out as follows:
+ // #0 - backdrop (content + caption)
+ // #1 - content (local bounds are at (0,0), will be translated and clipped to backdrop)
+ // #2 - additional overlay nodes
+ // Usually the backdrop cannot be seen since it will be entirely covered by the content. While
+ // resizing however it might become partially visible. The following render loop will crop the
+ // backdrop against the content and draw the remaining part of it. It will then draw the content
+ // cropped to the backdrop (since that indicates a shrinking of the window).
+ //
+ // Additional nodes will be drawn on top with no particular clipping semantics.
- // The bounds of the backdrop against which the content should be clipped.
- Rect backdropBounds = contentDrawBounds;
- // Usually the contents bounds should be mContentDrawBounds - however - we will
- // move it towards the fixed edge to give it a more stable appearance (for the moment).
- // If there is no content bounds we ignore the layering as stated above and start with 2.
- int layer = (contentDrawBounds.isEmpty() || nodes.size() == 1) ? 2 : 0;
+ // Usually the contents bounds should be mContentDrawBounds - however - we will
+ // move it towards the fixed edge to give it a more stable appearance (for the moment).
+ // If there is no content bounds we ignore the layering as stated above and start with 2.
- for (const sp<RenderNode>& node : nodes) {
- if (node->nothingToDraw()) continue;
+ // Backdrop bounds in render target space
+ const Rect backdrop = nodeBounds(*nodes[0]);
- SkASSERT(node->getDisplayList()->isSkiaDL());
+ // Bounds that content will fill in render target space (note content node bounds may be bigger)
+ Rect content(contentDrawBounds.getWidth(), contentDrawBounds.getHeight());
+ content.translate(backdrop.left, backdrop.top);
+ if (!content.contains(backdrop) && !nodes[0]->nothingToDraw()) {
+ // Content doesn't entirely overlap backdrop, so fill around content (right/bottom)
- int count = canvas->save();
-
- if (layer == 0) {
- const RenderProperties& properties = node->properties();
- Rect targetBounds(properties.getLeft(), properties.getTop(),
- properties.getRight(), properties.getBottom());
- // Move the content bounds towards the fixed corner of the backdrop.
- const int x = targetBounds.left;
- const int y = targetBounds.top;
- // Remember the intersection of the target bounds and the intersection bounds against
- // which we have to crop the content.
- backdropBounds.set(x, y, x + backdropBounds.getWidth(), y + backdropBounds.getHeight());
- backdropBounds.doIntersect(targetBounds);
- } else if (layer == 1) {
- // We shift and clip the content to match its final location in the window.
- const SkRect clip = SkRect::MakeXYWH(contentDrawBounds.left, contentDrawBounds.top,
- backdropBounds.getWidth(), backdropBounds.getHeight());
- const float dx = backdropBounds.left - contentDrawBounds.left;
- const float dy = backdropBounds.top - contentDrawBounds.top;
- canvas->translate(dx, dy);
- // It gets cropped against the bounds of the backdrop to stay inside.
- canvas->clipRect(clip);
+ // Note: in the future, if content doesn't snap to backdrop's left/top, this may need to
+ // also fill left/top. Currently, both 2up and freeform position content at the top/left of
+ // the backdrop, so this isn't necessary.
+ RenderNodeDrawable backdropNode(nodes[0].get(), canvas);
+ if (content.right < backdrop.right) {
+ // draw backdrop to right side of content
+ SkAutoCanvasRestore acr(canvas, true);
+ canvas->clipRect(SkRect::MakeLTRB(content.right, backdrop.top,
+ backdrop.right, backdrop.bottom));
+ backdropNode.draw(canvas);
+ }
+ if (content.bottom < backdrop.bottom) {
+ // draw backdrop to bottom of content
+ // Note: bottom fill uses content left/right, to avoid overdrawing left/right fill
+ SkAutoCanvasRestore acr(canvas, true);
+ canvas->clipRect(SkRect::MakeLTRB(content.left, content.bottom,
+ content.right, backdrop.bottom));
+ backdropNode.draw(canvas);
+ }
}
- RenderNodeDrawable root(node.get(), canvas);
- root.draw(canvas);
- canvas->restoreToCount(count);
- layer++;
+ RenderNodeDrawable contentNode(nodes[1].get(), canvas);
+ if (!backdrop.isEmpty()) {
+ // content node translation to catch up with backdrop
+ float dx = backdrop.left - contentDrawBounds.left;
+ float dy = backdrop.top - contentDrawBounds.top;
+
+ SkAutoCanvasRestore acr(canvas, true);
+ canvas->translate(dx, dy);
+ const SkRect contentLocalClip = SkRect::MakeXYWH(contentDrawBounds.left,
+ contentDrawBounds.top, backdrop.getWidth(), backdrop.getHeight());
+ canvas->clipRect(contentLocalClip);
+ contentNode.draw(canvas);
+ } else {
+ SkAutoCanvasRestore acr(canvas, true);
+ contentNode.draw(canvas);
+ }
+
+ // remaining overlay nodes, simply defer
+ for (size_t index = 2; index < nodes.size(); index++) {
+ if (!nodes[index]->nothingToDraw()) {
+ SkAutoCanvasRestore acr(canvas, true);
+ RenderNodeDrawable overlayNode(nodes[index].get(), canvas);
+ overlayNode.draw(canvas);
+ }
+ }
}
}