}
/**
+ * Sets whether the display list is a projection receiver - that its parent
+ * DisplayList should draw any descendent DisplayLists with
+ * ProjectBackwards=true directly on top of it. Default value is false.
+ */
+ public void setProjectionReceiver(boolean shouldRecieve) {
+ if (hasNativeDisplayList()) {
+ nSetProjectionReceiver(mFinalizer.mNativeDisplayList, shouldRecieve);
+ }
+ }
+
+ /**
* Sets the outline, defining the shape that casts a shadow.
*
* Deep copies the native path to simplify reference ownership.
private static native void nSetCaching(long displayList, boolean caching);
private static native void nSetClipToBounds(long displayList, boolean clipToBounds);
private static native void nSetProjectBackwards(long displayList, boolean shouldProject);
+ private static native void nSetProjectionReceiver(long displayList, boolean shouldRecieve);
private static native void nSetIsolatedZVolume(long displayList, boolean isolateZVolume);
private static native void nSetOutline(long displayList, long nativePath);
private static native void nSetAlpha(long displayList, float alpha);
* 1 PFLAG3_IS_LAID_OUT
* 1 PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT
* 1 PFLAG3_CALLED_SUPER
- * 1 PFLAG3_PROJECT_BACKGROUND
* |-------|-------|-------|-------|
*/
*/
static final int PFLAG3_CALLED_SUPER = 0x10;
- /**
- * Flag indicating that the background of this view will be drawn into a
- * display list and projected onto the closest parent projection surface.
- */
- static final int PFLAG3_PROJECT_BACKGROUND = 0x20;
-
/* End of masks for mPrivateFlags3 */
static final int DRAG_MASK = PFLAG2_DRAG_CAN_ACCEPT | PFLAG2_DRAG_HOVERED;
// Set up drawable properties that are view-independent.
displayList.setLeftTopRightBottom(bounds.left, bounds.top, bounds.right, bounds.bottom);
displayList.setProjectBackwards(drawable.isProjected());
+ displayList.setProjectionReceiver(true);
displayList.setClipToBounds(false);
return displayList;
}
displayList->setProjectBackwards(shouldProject);
}
+static void android_view_DisplayList_setProjectionReceiver(JNIEnv* env,
+ jobject clazz, jlong displayListPtr, jboolean shouldRecieve) {
+ DisplayList* displayList = reinterpret_cast<DisplayList*>(displayListPtr);
+ displayList->setProjectionReceiver(shouldRecieve);
+}
+
static void android_view_DisplayList_setOutline(JNIEnv* env,
jobject clazz, jlong displayListPtr, jlong outlinePathPtr) {
DisplayList* displayList = reinterpret_cast<DisplayList*>(displayListPtr);
{ "nSetAnimationMatrix", "(JJ)V", (void*) android_view_DisplayList_setAnimationMatrix },
{ "nSetClipToBounds", "(JZ)V", (void*) android_view_DisplayList_setClipToBounds },
{ "nSetIsolatedZVolume", "(JZ)V", (void*) android_view_DisplayList_setIsolatedZVolume },
- { "nSetProjectBackwards", "(JZ)V", (void*) android_view_DisplayList_setProjectBackwards },
+ { "nSetProjectBackwards", "(JZ)V", (void*) android_view_DisplayList_setProjectBackwards },
+ { "nSetProjectionReceiver","(JZ)V", (void*) android_view_DisplayList_setProjectionReceiver },
{ "nSetOutline", "(JJ)V", (void*) android_view_DisplayList_setOutline },
{ "nSetAlpha", "(JF)V", (void*) android_view_DisplayList_setAlpha },
{ "nSetHasOverlappingRendering", "(JZ)V",
mClipToBounds = true;
mIsolatedZVolume = true;
mProjectBackwards = false;
+ mProjectionReceiver = false;
mOutline.rewind();
mAlpha = 1;
mHasOverlappingRendering = true;
const mat4* transformFromProjectionSurface) {
m3dNodes.clear();
mProjectedNodes.clear();
+ if (mDisplayListData == NULL || mSize == 0) return;
// TODO: should avoid this calculation in most cases
// TODO: just calculate single matrix, down to all leaf composited elements
opState->mSkipInOrderDraw = false;
}
- if (mIsolatedZVolume) {
- // create a new 3d space for descendents by collecting them
- compositedChildrenOf3dRoot = &m3dNodes;
- transformFrom3dRoot = &mat4::identity();
- } else {
- applyViewPropertyTransforms(localTransformFrom3dRoot);
- transformFrom3dRoot = &localTransformFrom3dRoot;
- }
-
- if (mDisplayListData != NULL && mDisplayListData->projectionIndex >= 0) {
- // create a new projection surface for descendents by collecting them
- compositedChildrenOfProjectionSurface = &mProjectedNodes;
- transformFromProjectionSurface = &mat4::identity();
- } else {
- applyViewPropertyTransforms(localTransformFromProjectionSurface);
- transformFromProjectionSurface = &localTransformFromProjectionSurface;
- }
+ if (mDisplayListData->children.size() > 0) {
+ if (mIsolatedZVolume) {
+ // create a new 3d space for descendents by collecting them
+ compositedChildrenOf3dRoot = &m3dNodes;
+ transformFrom3dRoot = &mat4::identity();
+ } else {
+ applyViewPropertyTransforms(localTransformFrom3dRoot);
+ transformFrom3dRoot = &localTransformFrom3dRoot;
+ }
- if (mDisplayListData != NULL && mDisplayListData->children.size() > 0) {
+ const bool isProjectionReceiver = mDisplayListData->projectionReceiveIndex >= 0;
+ bool haveAppliedPropertiesToProjection = false;
for (unsigned int i = 0; i < mDisplayListData->children.size(); i++) {
DrawDisplayListOp* childOp = mDisplayListData->children[i];
- childOp->mDisplayList->computeOrderingImpl(childOp,
+ DisplayList* child = childOp->mDisplayList;
+
+ Vector<DrawDisplayListOp*>* projectionChildren = NULL;
+ const mat4* projectionTransform = NULL;
+ if (isProjectionReceiver && !child->mProjectBackwards) {
+ // if receiving projections, collect projecting descendent
+
+ // Note that if a direct descendent is projecting backwards, we pass it's
+ // grandparent projection collection, since it shouldn't project onto it's
+ // parent, where it will already be drawing.
+ projectionChildren = &mProjectedNodes;
+ projectionTransform = &mat4::identity();
+ } else {
+ if (!haveAppliedPropertiesToProjection) {
+ applyViewPropertyTransforms(localTransformFromProjectionSurface);
+ haveAppliedPropertiesToProjection = true;
+ }
+ projectionChildren = compositedChildrenOfProjectionSurface;
+ projectionTransform = &localTransformFromProjectionSurface;
+ }
+ child->computeOrderingImpl(childOp,
compositedChildrenOf3dRoot, transformFrom3dRoot,
- compositedChildrenOfProjectionSurface, transformFromProjectionSurface);
+ projectionChildren, projectionTransform);
}
}
+
}
class DeferOperationHandler {
return;
}
+ int rootRestoreTo = renderer.save(SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag);
LinearAllocator& alloc = handler.allocator();
ClipRectOp* clipOp = new (alloc) ClipRectOp(0, 0, mWidth, mHeight,
SkRegion::kIntersect_Op); // clip to 3d root bounds for now
handler(clipOp, PROPERTY_SAVECOUNT, mClipToBounds);
- int rootRestoreTo = renderer.save(SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag);
for (size_t i = 0; i < m3dNodes.size(); i++) {
const float zValue = m3dNodes[i].key;
template <class T>
void DisplayList::iterateProjectedChildren(OpenGLRenderer& renderer, T& handler, const int level) {
+ int rootRestoreTo = renderer.save(SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag);
LinearAllocator& alloc = handler.allocator();
ClipRectOp* clipOp = new (alloc) ClipRectOp(0, 0, mWidth, mHeight,
SkRegion::kReplace_Op); // clip to projection surface root bounds
handler(clipOp, PROPERTY_SAVECOUNT, mClipToBounds);
- int rootRestoreTo = renderer.save(SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag);
for (size_t i = 0; i < mProjectedNodes.size(); i++) {
DrawDisplayListOp* childOp = mProjectedNodes[i];
+
+ // matrix save, concat, and restore can be done safely without allocating operations
+ int restoreTo = renderer.save(SkCanvas::kMatrix_SaveFlag);
renderer.concatMatrix(childOp->mTransformFromCompositingAncestor);
childOp->mSkipInOrderDraw = false; // this is horrible, I'm so sorry everyone
handler(childOp, renderer.getSaveCount() - 1, mClipToBounds);
childOp->mSkipInOrderDraw = true;
+ renderer.restoreToCount(restoreTo);
}
handler(new (alloc) RestoreToCountOp(rootRestoreTo), PROPERTY_SAVECOUNT, mClipToBounds);
}
DisplayListLogBuffer& logBuffer = DisplayListLogBuffer::getInstance();
const int saveCountOffset = renderer.getSaveCount() - 1;
- const int projectionIndex = mDisplayListData->projectionIndex;
+ const int projectionReceiveIndex = mDisplayListData->projectionReceiveIndex;
for (unsigned int i = 0; i < mDisplayListData->displayListOps.size(); i++) {
DisplayListOp *op = mDisplayListData->displayListOps[i];
logBuffer.writeCommand(level, op->name());
handler(op, saveCountOffset, mClipToBounds);
- if (CC_UNLIKELY(i == projectionIndex && mProjectedNodes.size() > 0)) {
+ if (CC_UNLIKELY(i == projectionReceiveIndex && mProjectedNodes.size() > 0)) {
iterateProjectedChildren(renderer, handler, level);
}
}
*/
class DisplayListData : public LightRefBase<DisplayListData> {
public:
- DisplayListData() : projectionIndex(-1) {}
+ DisplayListData() : projectionReceiveIndex(-1) {}
// allocator into which all ops were allocated
LinearAllocator allocator;
Vector<DrawDisplayListOp*> children;
// index of DisplayListOp restore, after which projected descendents should be drawn
- int projectionIndex;
- Matrix4 projectionTransform;
+ int projectionReceiveIndex;
};
/**
mProjectBackwards = shouldProject;
}
+ void setProjectionReceiver(bool shouldRecieve) {
+ mProjectionReceiver = shouldRecieve;
+ }
+
+ bool isProjectionReceiver() {
+ return mProjectionReceiver;
+ }
+
void setOutline(const SkPath* outline) {
if (!outline) {
mOutline.reset();
bool mClipToBounds;
bool mIsolatedZVolume;
bool mProjectBackwards;
+ bool mProjectionReceiver;
SkPath mOutline;
float mAlpha;
bool mHasOverlappingRendering;
StatefulBaseRenderer::restoreToCount(saveCount);
}
-void DisplayListRenderer::onSnapshotRestored(const Snapshot& removed, const Snapshot& restored) {
- bool restoreProjection = removed.flags & Snapshot::kFlagProjectionTarget;
- if (restoreProjection) {
- mDisplayListData->projectionIndex = mDisplayListData->displayListOps.size() - 1;
- mDisplayListData->projectionTransform.load(*currentTransform());
- }
-}
-
int DisplayListRenderer::saveLayer(float left, float top, float right, float bottom,
int alpha, SkXfermode::Mode mode, int flags) {
addStateOp(new (alloc()) SaveLayerOp(left, top, right, bottom, alpha, mode, flags));
flags, *currentTransform());
addDrawOp(op);
mDisplayListData->children.push(op);
+ if (displayList->isProjectionReceiver()) {
+ mDisplayListData->projectionReceiveIndex = mDisplayListData->displayListOps.size() - 1;
+ }
return DrawGlInfo::kStatusDone;
}
uint32_t getFunctorCount() const {
return mFunctorCount;
}
-protected:
- virtual void onSnapshotRestored(const Snapshot& removed, const Snapshot& restored);
private:
void insertRestoreToCount();
} else {
region = NULL;
}
-
- if (saveFlags & Snapshot::kFlagProjectionTarget) {
- flags |= Snapshot::kFlagProjectionTarget;
- }
}
///////////////////////////////////////////////////////////////////////////////
* Indicates that this snapshot or an ancestor snapshot is
* an FBO layer.
*/
- kFlagFboTarget = 0x10,
- /**
- * Indicates that the save/restore pair encapsulates a
- * projection target, and that after the restore any projected
- * descendents should be drawn.
- */
- kFlagProjectionTarget = 0x20
+ kFlagFboTarget = 0x10
};
/**
<?xml version="1.0" encoding="utf-8"?>
-<view class="com.android.test.hwui.ProjectionActivity$ProjecteeLayout"
+<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
+ android:background="#66ff0000"
tools:context="com.example.projection.ProjectionActivity"
tools:ignore="MergeRootFrame">
<TextView
android:layout_height="100dp"
android:textSize="50sp"
android:text="TextView"/>
-</view>
\ No newline at end of file
+</LinearLayout>
\ No newline at end of file
}
}
- public static class ProjecteeLayout extends LinearLayout {
- private final Paint mPaint = new Paint();
- private final RectF mRectF = new RectF();
-
- public ProjecteeLayout(Context context) {
- this(context, null);
- }
-
- public ProjecteeLayout(Context context, AttributeSet attrs) {
- this(context, attrs, 0);
- }
-
- public ProjecteeLayout(Context context, AttributeSet attrs, int defStyle) {
- super(context, attrs, defStyle);
- }
-
- @Override
- protected void dispatchDraw(Canvas canvas) {
- canvas.save(0x20); // secret save flag
- mRectF.set(0, 0, getWidth(), getHeight());
- mPaint.setColor(0x5f000000);
- canvas.drawOval(mRectF, mPaint);
- canvas.restore();
- super.dispatchDraw(canvas);
- }
- }
-
static View container;
@Override