Merge "Expose display list APIs"

This commit is contained in:
Romain Guy
2013-02-19 20:32:13 +00:00
committed by Android (Google) Code Review
17 changed files with 927 additions and 242 deletions

View File

@ -19,13 +19,111 @@ package android.view;
import android.graphics.Matrix;
/**
* A display lists records a series of graphics related operation and can replay
* <p>A display list records a series of graphics related operations and can replay
* them later. Display lists are usually built by recording operations on a
* {@link android.graphics.Canvas}. Replaying the operations from a display list
* avoids executing views drawing code on every frame, and is thus much more
* efficient.
* {@link HardwareCanvas}. Replaying the operations from a display list avoids
* executing application code on every frame, and is thus much more efficient.</p>
*
* @hide
* <p>Display lists are used internally for all views by default, and are not
* typically used directly. One reason to consider using a display is a custom
* {@link View} implementation that needs to issue a large number of drawing commands.
* When the view invalidates, all the drawing commands must be reissued, even if
* large portions of the drawing command stream stay the same frame to frame, which
* can become a performance bottleneck. To solve this issue, a custom View might split
* its content into several display lists. A display list is updated only when its
* content, and only its content, needs to be updated.</p>
*
* <p>A text editor might for instance store each paragraph into its own display list.
* Thus when the user inserts or removes characters, only the display list of the
* affected paragraph needs to be recorded again.</p>
*
* <h3>Hardware acceleration</h3>
* <p>Display lists can only be replayed using a {@link HardwareCanvas}. They are not
* supported in software. Always make sure that the {@link android.graphics.Canvas}
* you are using to render a display list is hardware accelerated using
* {@link android.graphics.Canvas#isHardwareAccelerated()}.</p>
*
* <h3>Creating a display list</h3>
* <pre class="prettyprint">
* HardwareRenderer renderer = myView.getHardwareRenderer();
* if (renderer != null) {
* DisplayList displayList = renderer.createDisplayList();
* HardwareCanvas canvas = displayList.start(width, height);
* try {
* // Draw onto the canvas
* // For instance: canvas.drawBitmap(...);
* } finally {
* displayList.end();
* }
* }
* </pre>
*
* <h3>Rendering a display list on a View</h3>
* <pre class="prettyprint">
* @Override
* protected void onDraw(Canvas canvas) {
* if (canvas.isHardwareAccelerated()) {
* HardwareCanvas hardwareCanvas = (HardwareCanvas) canvas;
* hardwareCanvas.drawDisplayList(mDisplayList);
* }
* }
* </pre>
*
* <h3>Releasing resources</h3>
* <p>This step is not mandatory but recommended if you want to release resources
* held by a display list as soon as possible.</p>
* <pre class="prettyprint">
* // Mark this display list invalid, it cannot be used for drawing anymore,
* // and release resources held by this display list
* displayList.clear();
* </pre>
*
* <h3>Properties</h3>
* <p>In addition, a display list offers several properties, such as
* {@link #setScaleX(float)} or {@link #setLeft(int)}, that can be used to affect all
* the drawing commands recorded within. For instance, these properties can be used
* to move around a large number of images without re-issuing all the individual
* <code>drawBitmap()</code> calls.</p>
*
* <pre class="prettyprint">
* private void createDisplayList() {
* HardwareRenderer renderer = getHardwareRenderer();
* if (renderer != null) {
* mDisplayList = renderer.createDisplayList();
* HardwareCanvas canvas = mDisplayList.start(width, height);
* try {
* for (Bitmap b : mBitmaps) {
* canvas.drawBitmap(b, 0.0f, 0.0f, null);
* canvas.translate(0.0f, b.getHeight());
* }
* } finally {
* displayList.end();
* }
* }
* }
*
* @Override
* protected void onDraw(Canvas canvas) {
* if (canvas.isHardwareAccelerated()) {
* HardwareCanvas hardwareCanvas = (HardwareCanvas) canvas;
* hardwareCanvas.drawDisplayList(mDisplayList);
* }
* }
*
* private void moveContentBy(int x) {
* // This will move all the bitmaps recorded inside the display list
* // by x pixels to the right and redraw this view. All the commands
* // recorded in createDisplayList() won't be re-issued, only onDraw()
* // will be invoked and will execute very quickly
* mDisplayList.offsetLeftAndRight(x);
* invalidate();
* }
* </pre>
*
* <h3>Threading</h3>
* <p>Display lists must be created on and manipulated from the UI thread only.</p>
*
* @hide
*/
public abstract class DisplayList {
private boolean mDirty;
@ -36,6 +134,8 @@ public abstract class DisplayList {
* When this flag is set, draw operations lying outside of the bounds of the
* display list will be culled early. It is recommeneded to always set this
* flag.
*
* @hide
*/
public static final int FLAG_CLIP_CHILDREN = 0x1;
@ -44,14 +144,18 @@ public abstract class DisplayList {
/**
* Indicates that the display list is done drawing.
*
* @see HardwareCanvas#drawDisplayList(DisplayList, android.graphics.Rect, int)
* @see HardwareCanvas#drawDisplayList(DisplayList, android.graphics.Rect, int)
*
* @hide
*/
public static final int STATUS_DONE = 0x0;
/**
* Indicates that the display list needs another drawing pass.
*
* @see HardwareCanvas#drawDisplayList(DisplayList, android.graphics.Rect, int)
* @see HardwareCanvas#drawDisplayList(DisplayList, android.graphics.Rect, int)
*
* @hide
*/
public static final int STATUS_DRAW = 0x1;
@ -59,7 +163,9 @@ public abstract class DisplayList {
* Indicates that the display list needs to re-execute its GL functors.
*
* @see HardwareCanvas#drawDisplayList(DisplayList, android.graphics.Rect, int)
* @see HardwareCanvas#callDrawGLFunction(int)
* @see HardwareCanvas#callDrawGLFunction(int)
*
* @hide
*/
public static final int STATUS_INVOKE = 0x2;
@ -67,53 +173,79 @@ public abstract class DisplayList {
* Indicates that the display list performed GL drawing operations.
*
* @see HardwareCanvas#drawDisplayList(DisplayList, android.graphics.Rect, int)
*
* @hide
*/
public static final int STATUS_DREW = 0x4;
/**
* Starts recording the display list. All operations performed on the
* returned canvas are recorded and stored in this display list.
*
*
* Calling this method will mark the display list invalid until
* {@link #end()} is called. Only valid display lists can be replayed.
*
* @param width The width of the display list's viewport
* @param height The height of the display list's viewport
*
* @return A canvas to record drawing operations.
*
* @see #end()
* @see #isValid()
*/
public abstract HardwareCanvas start();
public abstract HardwareCanvas start(int width, int height);
/**
* Ends the recording for this display list. A display list cannot be
* replayed if recording is not finished.
* replayed if recording is not finished. Calling this method marks
* the display list valid and {@link #isValid()} will return true.
*
* @see #start(int, int)
* @see #isValid()
*/
public abstract void end();
/**
* Invalidates the display list, indicating that it should be repopulated
* with new drawing commands prior to being used again. Calling this method
* causes calls to {@link #isValid()} to return <code>false</code>.
*/
public abstract void invalidate();
/**
* Clears additional resources held onto by this display list. You should
* only invoke this method after {@link #invalidate()}.
* Clears resources held onto by this display list. After calling this method
* {@link #isValid()} will return false.
*
* @see #isValid()
*/
public abstract void clear();
/**
* Sets the dirty flag. When a display list is dirty, both
* {@link #invalidate()} and {@link #clear()} should be invoked whenever
* possible.
*
* @param dirty True to mark the display list dirty, false otherwise
* Sets the dirty flag. When a display list is dirty, {@link #clear()} should
* be invoked whenever possible.
*
* @see #isDirty()
* @see #clear()
*
* @hide
*/
public void setDirty(boolean dirty) {
mDirty = dirty;
public void markDirty() {
mDirty = true;
}
/**
* Removes the dirty flag. This method can be used to cancel a cleanup
* previously scheduled by setting the dirty flag.
*
* @see #isDirty()
* @see #clear()
*
* @hide
*/
protected void clearDirty() {
mDirty = false;
}
/**
* Indicates whether the display list is dirty.
*
* @see #setDirty(boolean)
* @see #markDirty()
* @see #clear()
*
* @hide
*/
public boolean isDirty() {
return mDirty;
@ -131,6 +263,8 @@ public abstract class DisplayList {
* Return the amount of memory used by this display list.
*
* @return The size of this display list in bytes
*
* @hide
*/
public abstract int getSize();
@ -139,228 +273,412 @@ public abstract class DisplayList {
///////////////////////////////////////////////////////////////////////////
/**
* Set the caching property on the DisplayList, which indicates whether the DisplayList
* holds a layer. Layer DisplayLists should avoid creating an alpha layer, since alpha is
* Set the caching property on the display list, which indicates whether the display list
* holds a layer. Layer display lists should avoid creating an alpha layer, since alpha is
* handled in the drawLayer operation directly (and more efficiently).
*
* @param caching true if the DisplayList represents a hardware layer, false otherwise.
* @param caching true if the display list represents a hardware layer, false otherwise.
*
* @hide
*/
public abstract void setCaching(boolean caching);
/**
* Set whether the DisplayList should clip itself to its bounds. This property is controlled by
* Set whether the display list should clip itself to its bounds. This property is controlled by
* the view's parent.
*
* @param clipChildren true if the DisplayList should clip to its bounds
* @param clipChildren true if the display list should clip to its bounds
*/
public abstract void setClipChildren(boolean clipChildren);
/**
* Set the static matrix on the DisplayList. This matrix exists if a custom ViewGroup
* overrides
* {@link ViewGroup#getChildStaticTransformation(View, android.view.animation.Transformation)}
* and also has {@link ViewGroup#setStaticTransformationsEnabled(boolean)} set to true.
* This matrix will be concatenated with any other matrices in the DisplayList to position
* the view appropriately.
* Set the static matrix on the display list. The specified matrix is combined with other
* transforms (such as {@link #setScaleX(float)}, {@link #setRotation(float)}, etc.)
*
* @param matrix The matrix
* @param matrix A transform matrix to apply to this display list
*
* @see #getMatrix(android.graphics.Matrix)
* @see #getMatrix()
*/
public abstract void setStaticMatrix(Matrix matrix);
public abstract void setMatrix(Matrix matrix);
/**
* Set the Animation matrix on the DisplayList. This matrix exists if an Animation is
* currently playing on a View, and is set on the DisplayList during at draw() time. When
* Returns the static matrix set on this display list.
*
* @return A new {@link Matrix} instance populated with this display list's static
* matrix
*
* @see #getMatrix(android.graphics.Matrix)
* @see #setMatrix(android.graphics.Matrix)
*/
public Matrix getMatrix() {
return getMatrix(new Matrix());
}
/**
* Copies this display list's static matrix into the specified matrix.
*
* @param matrix The {@link Matrix} instance in which to copy this display
* list's static matrix. Cannot be null
*
* @return The <code>matrix</code> parameter, for convenience
*
* @see #getMatrix()
* @see #setMatrix(android.graphics.Matrix)
*/
public abstract Matrix getMatrix(Matrix matrix);
/**
* Set the Animation matrix on the display list. This matrix exists if an Animation is
* currently playing on a View, and is set on the display list during at draw() time. When
* the Animation finishes, the matrix should be cleared by sending <code>null</code>
* for the matrix parameter.
*
* @param matrix The matrix, null indicates that the matrix should be cleared.
*
* @hide
*/
public abstract void setAnimationMatrix(Matrix matrix);
/**
* Sets the alpha value for the DisplayList
* Sets the translucency level for the display list.
*
* @param alpha The translucency of the display list, must be a value between 0.0f and 1.0f
*
* @param alpha The translucency of the DisplayList
* @see View#setAlpha(float)
* @see #getAlpha()
*/
public abstract void setAlpha(float alpha);
/**
* Sets whether the DisplayList renders content which overlaps. Non-overlapping rendering
* can use a fast path for alpha that avoids rendering to an offscreen buffer.
* Returns the translucency level of this display list.
*
* @return A value between 0.0f and 1.0f
*
* @see #setAlpha(float)
*/
public abstract float getAlpha();
/**
* Sets whether the display list renders content which overlaps. Non-overlapping rendering
* can use a fast path for alpha that avoids rendering to an offscreen buffer. By default
* display lists consider they do not have overlapping content.
*
* @param hasOverlappingRendering False if the content is guaranteed to be non-overlapping,
* true otherwise.
*
* @param hasOverlappingRendering
* @see android.view.View#hasOverlappingRendering()
* @see #hasOverlappingRendering()
*/
public abstract void setHasOverlappingRendering(boolean hasOverlappingRendering);
/**
* Sets the translationX value for the DisplayList
* Indicates whether the content of this display list overlaps.
*
* @return True if this display list renders content which overlaps, false otherwise.
*
* @see #setHasOverlappingRendering(boolean)
*/
public abstract boolean hasOverlappingRendering();
/**
* Sets the translation value for the display list on the X axis
*
* @param translationX The X axis translation value of the display list, in pixels
*
* @param translationX The translationX value of the DisplayList
* @see View#setTranslationX(float)
* @see #getTranslationX()
*/
public abstract void setTranslationX(float translationX);
/**
* Sets the translationY value for the DisplayList
* Returns the translation value for this display list on the X axis, in pixels.
*
* @see #setTranslationX(float)
*/
public abstract float getTranslationX();
/**
* Sets the translation value for the display list on the Y axis
*
* @param translationY The Y axis translation value of the display list, in pixels
*
* @param translationY The translationY value of the DisplayList
* @see View#setTranslationY(float)
* @see #getTranslationY()
*/
public abstract void setTranslationY(float translationY);
/**
* Sets the rotation value for the DisplayList
* Returns the translation value for this display list on the Y axis, in pixels.
*
* @see #setTranslationY(float)
*/
public abstract float getTranslationY();
/**
* Sets the rotation value for the display list around the Z axis
*
* @param rotation The rotation value of the display list, in degrees
*
* @param rotation The rotation value of the DisplayList
* @see View#setRotation(float)
* @see #getRotation()
*/
public abstract void setRotation(float rotation);
/**
* Sets the rotationX value for the DisplayList
* Returns the rotation value for this display list around the Z axis, in degrees.
*
* @see #setRotation(float)
*/
public abstract float getRotation();
/**
* Sets the rotation value for the display list around the X axis
*
* @param rotationX The rotation value of the display list, in degrees
*
* @param rotationX The rotationX value of the DisplayList
* @see View#setRotationX(float)
* @see #getRotationX()
*/
public abstract void setRotationX(float rotationX);
/**
* Sets the rotationY value for the DisplayList
* Returns the rotation value for this display list around the X axis, in degrees.
*
* @see #setRotationX(float)
*/
public abstract float getRotationX();
/**
* Sets the rotation value for the display list around the Y axis
*
* @param rotationY The rotation value of the display list, in degrees
*
* @param rotationY The rotationY value of the DisplayList
* @see View#setRotationY(float)
* @see #getRotationY()
*/
public abstract void setRotationY(float rotationY);
/**
* Sets the scaleX value for the DisplayList
* Returns the rotation value for this display list around the Y axis, in degrees.
*
* @see #setRotationY(float)
*/
public abstract float getRotationY();
/**
* Sets the scale value for the display list on the X axis
*
* @param scaleX The scale value of the display list
*
* @param scaleX The scaleX value of the DisplayList
* @see View#setScaleX(float)
* @see #getScaleX()
*/
public abstract void setScaleX(float scaleX);
/**
* Sets the scaleY value for the DisplayList
* Returns the scale value for this display list on the X axis.
*
* @see #setScaleX(float)
*/
public abstract float getScaleX();
/**
* Sets the scale value for the display list on the Y axis
*
* @param scaleY The scale value of the display list
*
* @param scaleY The scaleY value of the DisplayList
* @see View#setScaleY(float)
* @see #getScaleY()
*/
public abstract void setScaleY(float scaleY);
/**
* Sets all of the transform-related values of the View onto the DisplayList
* Returns the scale value for this display list on the Y axis.
*
* @param alpha The alpha value of the DisplayList
* @param translationX The translationX value of the DisplayList
* @param translationY The translationY value of the DisplayList
* @param rotation The rotation value of the DisplayList
* @param rotationX The rotationX value of the DisplayList
* @param rotationY The rotationY value of the DisplayList
* @param scaleX The scaleX value of the DisplayList
* @param scaleY The scaleY value of the DisplayList
* @see #setScaleY(float)
*/
public abstract float getScaleY();
/**
* Sets all of the transform-related values of the display list
*
* @param alpha The alpha value of the display list
* @param translationX The translationX value of the display list
* @param translationY The translationY value of the display list
* @param rotation The rotation value of the display list
* @param rotationX The rotationX value of the display list
* @param rotationY The rotationY value of the display list
* @param scaleX The scaleX value of the display list
* @param scaleY The scaleY value of the display list
*
* @hide
*/
public abstract void setTransformationInfo(float alpha, float translationX, float translationY,
float rotation, float rotationX, float rotationY, float scaleX, float scaleY);
/**
* Sets the pivotX value for the DisplayList
* Sets the pivot value for the display list on the X axis
*
* @param pivotX The pivot value of the display list on the X axis, in pixels
*
* @param pivotX The pivotX value of the DisplayList
* @see View#setPivotX(float)
* @see #getPivotX()
*/
public abstract void setPivotX(float pivotX);
/**
* Sets the pivotY value for the DisplayList
* Returns the pivot value for this display list on the X axis, in pixels.
*
* @see #setPivotX(float)
*/
public abstract float getPivotX();
/**
* Sets the pivot value for the display list on the Y axis
*
* @param pivotY The pivot value of the display list on the Y axis, in pixels
*
* @param pivotY The pivotY value of the DisplayList
* @see View#setPivotY(float)
* @see #getPivotY()
*/
public abstract void setPivotY(float pivotY);
/**
* Sets the camera distance for the DisplayList
* Returns the pivot value for this display list on the Y axis, in pixels.
*
* @see #setPivotY(float)
*/
public abstract float getPivotY();
/**
* Sets the camera distance for the display list. Refer to
* {@link View#setCameraDistance(float)} for more information on how to
* use this property.
*
* @param distance The distance in Z of the camera of the display list
*
* @param distance The distance in z of the camera of the DisplayList
* @see View#setCameraDistance(float)
* @see #getCameraDistance()
*/
public abstract void setCameraDistance(float distance);
/**
* Sets the left value for the DisplayList
* Returns the distance in Z of the camera of the display list.
*
* @see #setCameraDistance(float)
*/
public abstract float getCameraDistance();
/**
* Sets the left position for the display list.
*
* @param left The left position, in pixels, of the display list
*
* @param left The left value of the DisplayList
* @see View#setLeft(int)
* @see #getLeft()
*/
public abstract void setLeft(int left);
/**
* Sets the top value for the DisplayList
* Returns the left position for the display list in pixels.
*
* @see #setLeft(int)
*/
public abstract float getLeft();
/**
* Sets the top position for the display list.
*
* @param top The top position, in pixels, of the display list
*
* @param top The top value of the DisplayList
* @see View#setTop(int)
* @see #getTop()
*/
public abstract void setTop(int top);
/**
* Sets the right value for the DisplayList
* Returns the top position for the display list in pixels.
*
* @see #setTop(int)
*/
public abstract float getTop();
/**
* Sets the right position for the display list.
*
* @param right The right position, in pixels, of the display list
*
* @param right The right value of the DisplayList
* @see View#setRight(int)
* @see #getRight()
*/
public abstract void setRight(int right);
/**
* Sets the bottom value for the DisplayList
* Returns the right position for the display list in pixels.
*
* @see #setRight(int)
*/
public abstract float getRight();
/**
* Sets the bottom position for the display list.
*
* @param bottom The bottom position, in pixels, of the display list
*
* @param bottom The bottom value of the DisplayList
* @see View#setBottom(int)
* @see #getBottom()
*/
public abstract void setBottom(int bottom);
/**
* Sets the left and top values for the DisplayList
* Returns the bottom position for the display list in pixels.
*
* @param left The left value of the DisplayList
* @param top The top value of the DisplayList
* @see View#setLeft(int)
* @see View#setTop(int)
* @see #setBottom(int)
*/
public abstract void setLeftTop(int left, int top);
public abstract float getBottom();
/**
* Sets the left and top values for the DisplayList
* Sets the left and top positions for the display list
*
* @param left The left position of the display list, in pixels
* @param top The top position of the display list, in pixels
* @param right The right position of the display list, in pixels
* @param bottom The bottom position of the display list, in pixels
*
* @param left The left value of the DisplayList
* @param top The top value of the DisplayList
* @see View#setLeft(int)
* @see View#setTop(int)
* @see View#setRight(int)
* @see View#setBottom(int)
*/
public abstract void setLeftTopRightBottom(int left, int top, int right, int bottom);
/**
* Offsets the left and right values for the DisplayList
* Offsets the left and right positions for the display list
*
* @param offset The amount that the left and right positions of the display
* list are offset, in pixels
*
* @param offset The amount that the left and right values of the DisplayList are offset
* @see View#offsetLeftAndRight(int)
*/
public abstract void offsetLeftRight(int offset);
public abstract void offsetLeftAndRight(float offset);
/**
* Offsets the top and bottom values for the DisplayList
* Offsets the top and bottom values for the display list
*
* @param offset The amount that the top and bottom positions of the display
* list are offset, in pixels
*
* @param offset The amount that the top and bottom values of the DisplayList are offset
* @see View#offsetTopAndBottom(int)
*/
public abstract void offsetTopBottom(int offset);
public abstract void offsetTopAndBottom(float offset);
/**
* Reset native resources. This is called when cleaning up the state of DisplayLists
* Reset native resources. This is called when cleaning up the state of display lists
* during destruction of hardware resources, to ensure that we do not hold onto
* obsolete resources after related resources are gone.
*
* @hide
*/
public abstract void reset();
}

View File

@ -377,24 +377,13 @@ class GLES20Canvas extends HardwareCanvas {
}
private static native int nGetDisplayList(int renderer, int displayList);
static void destroyDisplayList(int displayList) {
nDestroyDisplayList(displayList);
@Override
void outputDisplayList(DisplayList displayList) {
nOutputDisplayList(mRenderer, ((GLES20DisplayList) displayList).getNativeDisplayList());
}
private static native void nDestroyDisplayList(int displayList);
static int getDisplayListSize(int displayList) {
return nGetDisplayListSize(displayList);
}
private static native int nGetDisplayListSize(int displayList);
static void setDisplayListName(int displayList, String name) {
nSetDisplayListName(displayList, name);
}
private static native void nSetDisplayListName(int displayList, String name);
private static native void nOutputDisplayList(int renderer, int displayList);
@Override
public int drawDisplayList(DisplayList displayList, Rect dirty, int flags) {
@ -405,13 +394,6 @@ class GLES20Canvas extends HardwareCanvas {
private static native int nDrawDisplayList(int renderer, int displayList,
Rect dirty, int flags);
@Override
void outputDisplayList(DisplayList displayList) {
nOutputDisplayList(mRenderer, ((GLES20DisplayList) displayList).getNativeDisplayList());
}
private static native void nOutputDisplayList(int renderer, int displayList);
///////////////////////////////////////////////////////////////////////////
// Hardware layer
///////////////////////////////////////////////////////////////////////////

View File

@ -58,7 +58,7 @@ class GLES20DisplayList extends DisplayList {
}
@Override
public HardwareCanvas start() {
public HardwareCanvas start(int width, int height) {
if (mCanvas != null) {
throw new IllegalStateException("Recording has already started");
}
@ -66,24 +66,25 @@ class GLES20DisplayList extends DisplayList {
mValid = false;
mCanvas = GLES20RecordingCanvas.obtain(this);
mCanvas.start();
mCanvas.setViewport(width, height);
// The dirty rect should always be null for a display list
mCanvas.onPreDraw(null);
return mCanvas;
}
@Override
public void invalidate() {
public void clear() {
clearDirty();
if (mCanvas != null) {
mCanvas.recycle();
mCanvas = null;
}
mValid = false;
}
@Override
public void clear() {
if (!mValid) {
mBitmaps.clear();
mChildDisplayLists.clear();
}
mBitmaps.clear();
mChildDisplayLists.clear();
}
@Override
@ -101,11 +102,12 @@ class GLES20DisplayList extends DisplayList {
@Override
public void end() {
if (mCanvas != null) {
mCanvas.onPostDraw();
if (mFinalizer != null) {
mCanvas.end(mFinalizer.mNativeDisplayList);
} else {
mFinalizer = new DisplayListFinalizer(mCanvas.end(0));
GLES20Canvas.setDisplayListName(mFinalizer.mNativeDisplayList, mName);
nSetDisplayListName(mFinalizer.mNativeDisplayList, mName);
}
mCanvas.recycle();
mCanvas = null;
@ -116,9 +118,13 @@ class GLES20DisplayList extends DisplayList {
@Override
public int getSize() {
if (mFinalizer == null) return 0;
return GLES20Canvas.getDisplayListSize(mFinalizer.mNativeDisplayList);
return nGetDisplayListSize(mFinalizer.mNativeDisplayList);
}
private static native void nDestroyDisplayList(int displayList);
private static native int nGetDisplayListSize(int displayList);
private static native void nSetDisplayListName(int displayList, String name);
///////////////////////////////////////////////////////////////////////////
// Native View Properties
///////////////////////////////////////////////////////////////////////////
@ -138,12 +144,20 @@ class GLES20DisplayList extends DisplayList {
}
@Override
public void setStaticMatrix(Matrix matrix) {
public void setMatrix(Matrix matrix) {
if (hasNativeDisplayList()) {
nSetStaticMatrix(mFinalizer.mNativeDisplayList, matrix.native_instance);
}
}
@Override
public Matrix getMatrix(Matrix matrix) {
if (hasNativeDisplayList()) {
nGetMatrix(mFinalizer.mNativeDisplayList, matrix.native_instance);
}
return matrix;
}
@Override
public void setAnimationMatrix(Matrix matrix) {
if (hasNativeDisplayList()) {
@ -159,6 +173,14 @@ class GLES20DisplayList extends DisplayList {
}
}
@Override
public float getAlpha() {
if (hasNativeDisplayList()) {
return nGetAlpha(mFinalizer.mNativeDisplayList);
}
return 1.0f;
}
@Override
public void setHasOverlappingRendering(boolean hasOverlappingRendering) {
if (hasNativeDisplayList()) {
@ -166,6 +188,15 @@ class GLES20DisplayList extends DisplayList {
}
}
@Override
public boolean hasOverlappingRendering() {
//noinspection SimplifiableIfStatement
if (hasNativeDisplayList()) {
return nHasOverlappingRendering(mFinalizer.mNativeDisplayList);
}
return true;
}
@Override
public void setTranslationX(float translationX) {
if (hasNativeDisplayList()) {
@ -173,6 +204,14 @@ class GLES20DisplayList extends DisplayList {
}
}
@Override
public float getTranslationX() {
if (hasNativeDisplayList()) {
return nGetTranslationX(mFinalizer.mNativeDisplayList);
}
return 0.0f;
}
@Override
public void setTranslationY(float translationY) {
if (hasNativeDisplayList()) {
@ -180,6 +219,14 @@ class GLES20DisplayList extends DisplayList {
}
}
@Override
public float getTranslationY() {
if (hasNativeDisplayList()) {
return nGetTranslationY(mFinalizer.mNativeDisplayList);
}
return 0.0f;
}
@Override
public void setRotation(float rotation) {
if (hasNativeDisplayList()) {
@ -187,6 +234,14 @@ class GLES20DisplayList extends DisplayList {
}
}
@Override
public float getRotation() {
if (hasNativeDisplayList()) {
return nGetRotation(mFinalizer.mNativeDisplayList);
}
return 0.0f;
}
@Override
public void setRotationX(float rotationX) {
if (hasNativeDisplayList()) {
@ -194,6 +249,14 @@ class GLES20DisplayList extends DisplayList {
}
}
@Override
public float getRotationX() {
if (hasNativeDisplayList()) {
return nGetRotationX(mFinalizer.mNativeDisplayList);
}
return 0.0f;
}
@Override
public void setRotationY(float rotationY) {
if (hasNativeDisplayList()) {
@ -201,6 +264,14 @@ class GLES20DisplayList extends DisplayList {
}
}
@Override
public float getRotationY() {
if (hasNativeDisplayList()) {
return nGetRotationY(mFinalizer.mNativeDisplayList);
}
return 0.0f;
}
@Override
public void setScaleX(float scaleX) {
if (hasNativeDisplayList()) {
@ -208,6 +279,14 @@ class GLES20DisplayList extends DisplayList {
}
}
@Override
public float getScaleX() {
if (hasNativeDisplayList()) {
return nGetScaleX(mFinalizer.mNativeDisplayList);
}
return 1.0f;
}
@Override
public void setScaleY(float scaleY) {
if (hasNativeDisplayList()) {
@ -215,6 +294,14 @@ class GLES20DisplayList extends DisplayList {
}
}
@Override
public float getScaleY() {
if (hasNativeDisplayList()) {
return nGetScaleY(mFinalizer.mNativeDisplayList);
}
return 1.0f;
}
@Override
public void setTransformationInfo(float alpha, float translationX, float translationY,
float rotation, float rotationX, float rotationY, float scaleX, float scaleY) {
@ -231,6 +318,14 @@ class GLES20DisplayList extends DisplayList {
}
}
@Override
public float getPivotX() {
if (hasNativeDisplayList()) {
return nGetPivotX(mFinalizer.mNativeDisplayList);
}
return 0.0f;
}
@Override
public void setPivotY(float pivotY) {
if (hasNativeDisplayList()) {
@ -238,6 +333,14 @@ class GLES20DisplayList extends DisplayList {
}
}
@Override
public float getPivotY() {
if (hasNativeDisplayList()) {
return nGetPivotY(mFinalizer.mNativeDisplayList);
}
return 0.0f;
}
@Override
public void setCameraDistance(float distance) {
if (hasNativeDisplayList()) {
@ -245,6 +348,14 @@ class GLES20DisplayList extends DisplayList {
}
}
@Override
public float getCameraDistance() {
if (hasNativeDisplayList()) {
return nGetCameraDistance(mFinalizer.mNativeDisplayList);
}
return 0.0f;
}
@Override
public void setLeft(int left) {
if (hasNativeDisplayList()) {
@ -252,6 +363,14 @@ class GLES20DisplayList extends DisplayList {
}
}
@Override
public float getLeft() {
if (hasNativeDisplayList()) {
return nGetLeft(mFinalizer.mNativeDisplayList);
}
return 0.0f;
}
@Override
public void setTop(int top) {
if (hasNativeDisplayList()) {
@ -259,6 +378,14 @@ class GLES20DisplayList extends DisplayList {
}
}
@Override
public float getTop() {
if (hasNativeDisplayList()) {
return nGetTop(mFinalizer.mNativeDisplayList);
}
return 0.0f;
}
@Override
public void setRight(int right) {
if (hasNativeDisplayList()) {
@ -266,6 +393,14 @@ class GLES20DisplayList extends DisplayList {
}
}
@Override
public float getRight() {
if (hasNativeDisplayList()) {
return nGetRight(mFinalizer.mNativeDisplayList);
}
return 0.0f;
}
@Override
public void setBottom(int bottom) {
if (hasNativeDisplayList()) {
@ -274,10 +409,11 @@ class GLES20DisplayList extends DisplayList {
}
@Override
public void setLeftTop(int left, int top) {
public float getBottom() {
if (hasNativeDisplayList()) {
nSetLeftTop(mFinalizer.mNativeDisplayList, left, top);
return nGetBottom(mFinalizer.mNativeDisplayList);
}
return 0.0f;
}
@Override
@ -288,25 +424,24 @@ class GLES20DisplayList extends DisplayList {
}
@Override
public void offsetLeftRight(int offset) {
public void offsetLeftAndRight(float offset) {
if (hasNativeDisplayList()) {
nOffsetLeftRight(mFinalizer.mNativeDisplayList, offset);
nOffsetLeftAndRight(mFinalizer.mNativeDisplayList, offset);
}
}
@Override
public void offsetTopBottom(int offset) {
public void offsetTopAndBottom(float offset) {
if (hasNativeDisplayList()) {
nOffsetTopBottom(mFinalizer.mNativeDisplayList, offset);
nOffsetTopAndBottom(mFinalizer.mNativeDisplayList, offset);
}
}
private static native void nReset(int displayList);
private static native void nOffsetTopBottom(int displayList, int offset);
private static native void nOffsetLeftRight(int displayList, int offset);
private static native void nOffsetTopAndBottom(int displayList, float offset);
private static native void nOffsetLeftAndRight(int displayList, float offset);
private static native void nSetLeftTopRightBottom(int displayList, int left, int top,
int right, int bottom);
private static native void nSetLeftTop(int displayList, int left, int top);
private static native void nSetBottom(int displayList, int bottom);
private static native void nSetRight(int displayList, int right);
private static native void nSetTop(int displayList, int top);
@ -332,6 +467,23 @@ class GLES20DisplayList extends DisplayList {
private static native void nSetStaticMatrix(int displayList, int nativeMatrix);
private static native void nSetAnimationMatrix(int displayList, int animationMatrix);
private static native boolean nHasOverlappingRendering(int displayList);
private static native void nGetMatrix(int displayList, int matrix);
private static native float nGetAlpha(int displayList);
private static native float nGetLeft(int displayList);
private static native float nGetTop(int displayList);
private static native float nGetRight(int displayList);
private static native float nGetBottom(int displayList);
private static native float nGetCameraDistance(int displayList);
private static native float nGetScaleX(int displayList);
private static native float nGetScaleY(int displayList);
private static native float nGetTranslationX(int displayList);
private static native float nGetTranslationY(int displayList);
private static native float nGetRotation(int displayList);
private static native float nGetRotationX(int displayList);
private static native float nGetRotationY(int displayList);
private static native float nGetPivotX(int displayList);
private static native float nGetPivotY(int displayList);
///////////////////////////////////////////////////////////////////////////
// Finalization
@ -347,7 +499,7 @@ class GLES20DisplayList extends DisplayList {
@Override
protected void finalize() throws Throwable {
try {
GLES20Canvas.destroyDisplayList(mNativeDisplayList);
nDestroyDisplayList(mNativeDisplayList);
} finally {
super.finalize();
}

View File

@ -53,12 +53,12 @@ abstract class GLES20Layer extends HardwareLayer {
}
@Override
boolean copyInto(Bitmap bitmap) {
public boolean copyInto(Bitmap bitmap) {
return GLES20Canvas.nCopyLayer(mLayer, bitmap.mNativeBitmap);
}
@Override
void destroy() {
public void destroy() {
if (mFinalizer != null) {
mFinalizer.destroy();
mFinalizer = null;

View File

@ -92,6 +92,10 @@ class GLES20RenderLayer extends GLES20Layer {
if (currentCanvas instanceof GLES20Canvas) {
((GLES20Canvas) currentCanvas).resume();
}
HardwareCanvas canvas = getCanvas();
if (canvas != null) {
canvas.onPostDraw();
}
}
@Override
@ -99,7 +103,10 @@ class GLES20RenderLayer extends GLES20Layer {
if (currentCanvas instanceof GLES20Canvas) {
((GLES20Canvas) currentCanvas).interrupt();
}
return getCanvas();
HardwareCanvas canvas = getCanvas();
canvas.setViewport(mWidth, mHeight);
canvas.onPreDraw(null);
return canvas;
}
/**

View File

@ -23,8 +23,8 @@ import android.graphics.Rect;
/**
* Hardware accelerated canvas.
*
* @hide
*
* @hide
*/
public abstract class HardwareCanvas extends Canvas {
private String mName;
@ -46,6 +46,8 @@ public abstract class HardwareCanvas extends Canvas {
* @param name The name of the canvas, can be null
*
* @see #getName()
*
* @hide
*/
public void setName(String name) {
mName = name;
@ -57,6 +59,8 @@ public abstract class HardwareCanvas extends Canvas {
* @return The name of the canvas or null
*
* @see #setName(String)
*
* @hide
*/
public String getName() {
return mName;
@ -67,27 +71,43 @@ public abstract class HardwareCanvas extends Canvas {
*
* @param dirty The dirty rectangle to update, can be null.
* @return {@link DisplayList#STATUS_DREW} if anything was drawn (such as a call to clear
* the canvas).
* the canvas).
*
* @hide
*/
public abstract int onPreDraw(Rect dirty);
/**
* Invoked after all drawing operation have been performed.
*
* @hide
*/
public abstract void onPostDraw();
/**
* Draws the specified display list onto this canvas. The display list can only
* be drawn if {@link android.view.DisplayList#isValid()} returns true.
*
* @param displayList The display list to replay.
*/
public void drawDisplayList(DisplayList displayList) {
drawDisplayList(displayList, null, DisplayList.FLAG_CLIP_CHILDREN);
}
/**
* Draws the specified display list onto this canvas.
*
* @param displayList The display list to replay.
* @param dirty The dirty region to redraw in the next pass, matters only
* if this method returns true, can be null.
* if this method returns {@link DisplayList#STATUS_DRAW}, can be null.
* @param flags Optional flags about drawing, see {@link DisplayList} for
* the possible flags.
*
* @return One of {@link DisplayList#STATUS_DONE}, {@link DisplayList#STATUS_DRAW}, or
* {@link DisplayList#STATUS_INVOKE}, or'd with {@link DisplayList#STATUS_DREW}
* if anything was drawn.
*
* @hide
*/
public abstract int drawDisplayList(DisplayList displayList, Rect dirty, int flags);
@ -96,6 +116,8 @@ public abstract class HardwareCanvas extends Canvas {
* tools to output display lists for selected nodes to the log.
*
* @param displayList The display list to be logged.
*
* @hide
*/
abstract void outputDisplayList(DisplayList displayList);
@ -106,6 +128,8 @@ public abstract class HardwareCanvas extends Canvas {
* @param x The left coordinate of the layer
* @param y The top coordinate of the layer
* @param paint The paint used to draw the layer
*
* @hide
*/
abstract void drawHardwareLayer(HardwareLayer layer, float x, float y, Paint paint);
@ -118,6 +142,8 @@ public abstract class HardwareCanvas extends Canvas {
*
* @return One of {@link DisplayList#STATUS_DONE}, {@link DisplayList#STATUS_DRAW} or
* {@link DisplayList#STATUS_INVOKE}
*
* @hide
*/
public int callDrawGLFunction(int drawGLFunction) {
// Noop - this is done in the display list recorder subclass
@ -131,6 +157,8 @@ public abstract class HardwareCanvas extends Canvas {
*
* @return One of {@link DisplayList#STATUS_DONE}, {@link DisplayList#STATUS_DRAW} or
* {@link DisplayList#STATUS_INVOKE}
*
* @hide
*/
public int invokeFunctors(Rect dirty) {
return DisplayList.STATUS_DONE;
@ -143,7 +171,9 @@ public abstract class HardwareCanvas extends Canvas {
*
* @see #invokeFunctors(android.graphics.Rect)
* @see #callDrawGLFunction(int)
* @see #detachFunctor(int)
* @see #detachFunctor(int)
*
* @hide
*/
abstract void detachFunctor(int functor);
@ -154,7 +184,9 @@ public abstract class HardwareCanvas extends Canvas {
*
* @see #invokeFunctors(android.graphics.Rect)
* @see #callDrawGLFunction(int)
* @see #detachFunctor(int)
* @see #detachFunctor(int)
*
* @hide
*/
abstract void attachFunctor(int functor);
@ -164,13 +196,17 @@ public abstract class HardwareCanvas extends Canvas {
* @param layer The layer to update
*
* @see #clearLayerUpdates()
*
* @hide
*/
abstract void pushLayerUpdate(HardwareLayer layer);
/**
* Removes all enqueued layer updates.
*
* @see #pushLayerUpdate(HardwareLayer)
* @see #pushLayerUpdate(HardwareLayer)
*
* @hide
*/
abstract void clearLayerUpdates();
}

View File

@ -24,7 +24,7 @@ import android.graphics.Rect;
/**
* A hardware layer can be used to render graphics operations into a hardware
* friendly buffer. For instance, with an OpenGL backend, a hardware layer
* friendly buffer. For instance, with an OpenGL backend a hardware layer
* would use a Frame Buffer Object (FBO.) The hardware layer can be used as
* a drawing cache when a complex set of graphics operations needs to be
* drawn several times.
@ -68,7 +68,7 @@ abstract class HardwareLayer {
* @param paint The paint used when the layer is drawn into the destination canvas.
* @see View#setLayerPaint(android.graphics.Paint)
*/
void setLayerPaint(Paint paint) {}
void setLayerPaint(Paint paint) { }
/**
* Returns the minimum width of the layer.
@ -144,6 +144,9 @@ abstract class HardwareLayer {
* this layer.
*
* @return A hardware canvas, or null if a canvas cannot be created
*
* @see #start(android.graphics.Canvas)
* @see #end(android.graphics.Canvas)
*/
abstract HardwareCanvas getCanvas();
@ -154,12 +157,14 @@ abstract class HardwareLayer {
/**
* This must be invoked before drawing onto this layer.
*
* @param currentCanvas
*/
abstract HardwareCanvas start(Canvas currentCanvas);
/**
* This must be invoked after drawing onto this layer.
*
* @param currentCanvas
*/
abstract void end(Canvas currentCanvas);

View File

@ -49,7 +49,7 @@ import static javax.microedition.khronos.egl.EGL10.*;
/**
* Interface for rendering a view hierarchy using hardware acceleration.
*
*
* @hide
*/
public abstract class HardwareRenderer {
@ -63,9 +63,9 @@ public abstract class HardwareRenderer {
/**
* Turn on to only refresh the parts of the screen that need updating.
* When turned on the property defined by {@link #RENDER_DIRTY_REGIONS_PROPERTY}
* must also have the value "true".
* must also have the value "true".
*/
public static final boolean RENDER_DIRTY_REGIONS = true;
static final boolean RENDER_DIRTY_REGIONS = true;
/**
* System property used to enable or disable dirty regions invalidation.
@ -353,6 +353,8 @@ public abstract class HardwareRenderer {
* resources.
*
* @param cacheDir A directory the current process can write to
*
* @hide
*/
public static void setupDiskCache(File cacheDir) {
nSetupShadersDiskCache(new File(cacheDir, CACHE_PATH_SHADERS).getAbsolutePath());
@ -439,14 +441,25 @@ public abstract class HardwareRenderer {
abstract boolean draw(View view, View.AttachInfo attachInfo, HardwareDrawCallbacks callbacks,
Rect dirty);
/**
* Creates a new display list that can be used to record batches of
* drawing operations.
*
* @return A new display list.
*/
public DisplayList createDisplayList() {
return createDisplayList(null);
}
/**
* Creates a new display list that can be used to record batches of
* drawing operations.
*
* @param name The name of the display list, used for debugging purpose.
* May be null
* @param name The name of the display list, used for debugging purpose. May be null.
*
* @return A new display list.
*
* @hide
*/
public abstract DisplayList createDisplayList(String name);
@ -474,7 +487,6 @@ public abstract class HardwareRenderer {
/**
* Creates a new {@link SurfaceTexture} that can be used to render into the
* specified hardware layer.
*
*
* @param layer The layer to render into using a {@link android.graphics.SurfaceTexture}
*
@ -1971,12 +1983,12 @@ public abstract class HardwareRenderer {
}
@Override
HardwareLayer createHardwareLayer(int width, int height, boolean isOpaque) {
public HardwareLayer createHardwareLayer(int width, int height, boolean isOpaque) {
return new GLES20RenderLayer(width, height, isOpaque);
}
@Override
SurfaceTexture createSurfaceTexture(HardwareLayer layer) {
public SurfaceTexture createSurfaceTexture(HardwareLayer layer) {
return ((GLES20TextureLayer) layer).getSurfaceTexture();
}

View File

@ -16,7 +16,6 @@
package android.view;
import android.app.ActivityThread;
import android.content.ClipData;
import android.content.Context;
import android.content.res.Configuration;
@ -10050,7 +10049,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
mTop += offset;
mBottom += offset;
if (mDisplayList != null) {
mDisplayList.offsetTopBottom(offset);
mDisplayList.offsetTopAndBottom(offset);
invalidateViewProperty(false, false);
} else {
if (!matrixIsIdentity) {
@ -10098,7 +10097,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
mLeft += offset;
mRight += offset;
if (mDisplayList != null) {
mDisplayList.offsetLeftRight(offset);
mDisplayList.offsetLeftAndRight(offset);
invalidateViewProperty(false, false);
} else {
if (!matrixIsIdentity) {
@ -11687,7 +11686,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
}
if (mDisplayList != null) {
mDisplayList.setDirty(false);
mDisplayList.clearDirty();
}
}
@ -11966,7 +11965,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
if (mAttachInfo != null) {
if (mDisplayList != null) {
mDisplayList.setDirty(true);
mDisplayList.markDirty();
mAttachInfo.mViewRootImpl.enqueueDisplayList(mDisplayList);
}
mAttachInfo.mViewRootImpl.cancelInvalidate(this);
@ -12670,8 +12669,9 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
}
/**
* @return The HardwareRenderer associated with that view or null if hardware rendering
* is not supported or this this has not been attached to a window.
* @return The {@link HardwareRenderer} associated with that view or null if
* hardware rendering is not supported or this view is not attached
* to a window.
*
* @hide
*/
@ -12726,15 +12726,13 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
}
boolean caching = false;
final HardwareCanvas canvas = displayList.start();
int width = mRight - mLeft;
int height = mBottom - mTop;
int layerType = getLayerType();
final HardwareCanvas canvas = displayList.start(width, height);
try {
canvas.setViewport(width, height);
// The dirty rect should always be null for a display list
canvas.onPreDraw(null);
if (!isLayer && layerType != LAYER_TYPE_NONE) {
if (layerType == LAYER_TYPE_HARDWARE) {
final HardwareLayer layer = getHardwareLayer();
@ -12772,8 +12770,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
}
}
} finally {
canvas.onPostDraw();
displayList.end();
displayList.setCaching(caching);
if (isLayer) {
@ -12818,7 +12814,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
private void clearDisplayList() {
if (mDisplayList != null) {
mDisplayList.invalidate();
mDisplayList.clear();
}
}
@ -13394,7 +13389,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
alpha = transform.getAlpha();
}
if ((transformType & Transformation.TYPE_MATRIX) != 0) {
displayList.setStaticMatrix(transform.getMatrix());
displayList.setMatrix(transform.getMatrix());
}
}
}

View File

@ -4413,7 +4413,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
v.mTop += offset;
v.mBottom += offset;
if (v.mDisplayList != null) {
v.mDisplayList.offsetTopBottom(offset);
v.mDisplayList.offsetTopAndBottom(offset);
invalidateViewProperty(false, false);
}
}

View File

@ -1437,8 +1437,6 @@ public final class ViewRootImpl implements ViewParent,
}
// TODO: should handle create/resize failure
layerCanvas = mResizeBuffer.start(hwRendererCanvas);
layerCanvas.setViewport(mWidth, mHeight);
layerCanvas.onPreDraw(null);
final int restoreCount = layerCanvas.save();
int yoff;
@ -1475,9 +1473,6 @@ public final class ViewRootImpl implements ViewParent,
} catch (OutOfMemoryError e) {
Log.w(TAG, "Not enough memory for content change anim buffer", e);
} finally {
if (layerCanvas != null) {
layerCanvas.onPostDraw();
}
if (mResizeBuffer != null) {
mResizeBuffer.end(hwRendererCanvas);
if (!completed) {
@ -2506,9 +2501,7 @@ public final class ViewRootImpl implements ViewParent,
for (int i = 0; i < count; i++) {
final DisplayList displayList = displayLists.get(i);
if (displayList.isDirty()) {
displayList.invalidate();
displayList.clear();
displayList.setDirty(false);
}
}

View File

@ -1314,7 +1314,7 @@ public class Editor {
blockDisplayList = mTextDisplayLists[blockIndex] =
mTextView.getHardwareRenderer().createDisplayList("Text " + blockIndex);
} else {
if (blockIsInvalid) blockDisplayList.invalidate();
if (blockIsInvalid) blockDisplayList.clear();
}
final boolean blockDisplayListIsInvalid = !blockDisplayList.isValid();
@ -1337,19 +1337,16 @@ public class Editor {
// Rebuild display list if it is invalid
if (blockDisplayListIsInvalid) {
final HardwareCanvas hardwareCanvas = blockDisplayList.start();
final HardwareCanvas hardwareCanvas = blockDisplayList.start(
right - left, bottom - top);
try {
// Tighten the bounds of the viewport to the actual text size
hardwareCanvas.setViewport(right - left, bottom - top);
// The dirty rect should always be null for a display list
hardwareCanvas.onPreDraw(null);
// drawText is always relative to TextView's origin, this translation brings
// this range of text back to the top left corner of the viewport
// drawText is always relative to TextView's origin, this translation
// brings this range of text back to the top left corner of the viewport
hardwareCanvas.translate(-left, -top);
layout.drawText(hardwareCanvas, blockBeginLine, blockEndLine);
// No need to untranslate, previous context is popped after drawDisplayList
// No need to untranslate, previous context is popped after
// drawDisplayList
} finally {
hardwareCanvas.onPostDraw();
blockDisplayList.end();
// Same as drawDisplayList below, handled by our TextView's parent
blockDisplayList.setClipChildren(false);
@ -1430,7 +1427,7 @@ public class Editor {
while (i < numberOfBlocks) {
final int blockIndex = blockIndices[i];
if (blockIndex != DynamicLayout.INVALID_BLOCK_INDEX) {
mTextDisplayLists[blockIndex].invalidate();
mTextDisplayLists[blockIndex].clear();
}
if (blockEndLines[i] >= lastLine) break;
i++;
@ -1441,7 +1438,7 @@ public class Editor {
void invalidateTextDisplayList() {
if (mTextDisplayLists != null) {
for (int i = 0; i < mTextDisplayLists.length; i++) {
if (mTextDisplayLists[i] != null) mTextDisplayLists[i].invalidate();
if (mTextDisplayLists[i] != null) mTextDisplayLists[i].clear();
}
}
}

View File

@ -41,6 +41,7 @@
#include <SkTemplates.h>
#include <SkXfermode.h>
#include <DisplayList.h>
#include <DisplayListRenderer.h>
#include <LayerRenderer.h>
#include <OpenGLRenderer.h>
@ -716,20 +717,6 @@ static DisplayList* android_view_GLES20Canvas_getDisplayList(JNIEnv* env,
return renderer->getDisplayList(displayList);
}
static jint android_view_GLES20Canvas_getDisplayListSize(JNIEnv* env,
jobject clazz, DisplayList* displayList) {
return displayList->getSize();
}
static void android_view_GLES20Canvas_setDisplayListName(JNIEnv* env,
jobject clazz, DisplayList* displayList, jstring name) {
if (name != NULL) {
const char* textArray = env->GetStringUTFChars(name, NULL);
displayList->setName(textArray);
env->ReleaseStringUTFChars(name, textArray);
}
}
static OpenGLRenderer* android_view_GLES20Canvas_createDisplayListRenderer(JNIEnv* env,
jobject clazz) {
return new DisplayListRenderer;
@ -740,11 +727,6 @@ static void android_view_GLES20Canvas_resetDisplayListRenderer(JNIEnv* env,
renderer->reset();
}
static void android_view_GLES20Canvas_destroyDisplayList(JNIEnv* env,
jobject clazz, DisplayList* displayList) {
DisplayList::destroyDisplayListDeferred(displayList);
}
static jint android_view_GLES20Canvas_drawDisplayList(JNIEnv* env,
jobject clazz, OpenGLRenderer* renderer, DisplayList* displayList,
jobject dirty, jint flags) {
@ -1044,17 +1026,13 @@ static JNINativeMethod gMethods[] = {
(void*) android_view_GLES20Canvas_getClipBounds },
{ "nGetDisplayList", "(II)I", (void*) android_view_GLES20Canvas_getDisplayList },
{ "nDestroyDisplayList", "(I)V", (void*) android_view_GLES20Canvas_destroyDisplayList },
{ "nGetDisplayListSize", "(I)I", (void*) android_view_GLES20Canvas_getDisplayListSize },
{ "nSetDisplayListName", "(ILjava/lang/String;)V",
(void*) android_view_GLES20Canvas_setDisplayListName },
{ "nOutputDisplayList", "(II)V", (void*) android_view_GLES20Canvas_outputDisplayList },
{ "nDrawDisplayList", "(IILandroid/graphics/Rect;I)I",
(void*) android_view_GLES20Canvas_drawDisplayList },
{ "nCreateDisplayListRenderer", "()I", (void*) android_view_GLES20Canvas_createDisplayListRenderer },
{ "nResetDisplayListRenderer", "(I)V", (void*) android_view_GLES20Canvas_resetDisplayListRenderer },
{ "nOutputDisplayList", "(II)V", (void*) android_view_GLES20Canvas_outputDisplayList },
{ "nInterrupt", "(I)V", (void*) android_view_GLES20Canvas_interrupt },
{ "nResume", "(I)V", (void*) android_view_GLES20Canvas_resume },

View File

@ -23,6 +23,7 @@
#include <nativehelper/JNIHelp.h>
#include <android_runtime/AndroidRuntime.h>
#include <DisplayList.h>
#include <DisplayListRenderer.h>
namespace android {
@ -36,11 +37,34 @@ using namespace uirenderer;
*/
#ifdef USE_OPENGL_RENDERER
// ----------------------------------------------------------------------------
// DisplayList view properties
// ----------------------------------------------------------------------------
static void android_view_GLES20DisplayList_reset(JNIEnv* env,
jobject clazz, DisplayList* displayList) {
displayList->reset();
}
static jint android_view_GLES20DisplayList_getDisplayListSize(JNIEnv* env,
jobject clazz, DisplayList* displayList) {
return displayList->getSize();
}
static void android_view_GLES20DisplayList_setDisplayListName(JNIEnv* env,
jobject clazz, DisplayList* displayList, jstring name) {
if (name != NULL) {
const char* textArray = env->GetStringUTFChars(name, NULL);
displayList->setName(textArray);
env->ReleaseStringUTFChars(name, textArray);
}
}
static void android_view_GLES20DisplayList_destroyDisplayList(JNIEnv* env,
jobject clazz, DisplayList* displayList) {
DisplayList::destroyDisplayListDeferred(displayList);
}
// ----------------------------------------------------------------------------
// DisplayList view properties
// ----------------------------------------------------------------------------
@ -159,27 +183,112 @@ static void android_view_GLES20DisplayList_setBottom(JNIEnv* env,
displayList->setBottom(bottom);
}
static void android_view_GLES20DisplayList_setLeftTop(JNIEnv* env,
jobject clazz, DisplayList* displayList, int left, int top) {
displayList->setLeftTop(left, top);
}
static void android_view_GLES20DisplayList_setLeftTopRightBottom(JNIEnv* env,
jobject clazz, DisplayList* displayList, int left, int top,
int right, int bottom) {
displayList->setLeftTopRightBottom(left, top, right, bottom);
}
static void android_view_GLES20DisplayList_offsetLeftRight(JNIEnv* env,
jobject clazz, DisplayList* displayList, int offset) {
static void android_view_GLES20DisplayList_offsetLeftAndRight(JNIEnv* env,
jobject clazz, DisplayList* displayList, float offset) {
displayList->offsetLeftRight(offset);
}
static void android_view_GLES20DisplayList_offsetTopBottom(JNIEnv* env,
jobject clazz, DisplayList* displayList, int offset) {
static void android_view_GLES20DisplayList_offsetTopAndBottom(JNIEnv* env,
jobject clazz, DisplayList* displayList, float offset) {
displayList->offsetTopBottom(offset);
}
static void android_view_GLES20DisplayList_getMatrix(JNIEnv* env,
jobject clazz, DisplayList* displayList, SkMatrix* matrix) {
SkMatrix* source = displayList->getStaticMatrix();
if (source) {
matrix->setConcat(SkMatrix::I(), *source);
} else {
matrix->setIdentity();
}
}
static jboolean android_view_GLES20DisplayList_hasOverlappingRendering(JNIEnv* env,
jobject clazz, DisplayList* displayList) {
return displayList->hasOverlappingRendering();
}
static jfloat android_view_GLES20DisplayList_getAlpha(JNIEnv* env,
jobject clazz, DisplayList* displayList) {
return displayList->getAlpha();
}
static jfloat android_view_GLES20DisplayList_getLeft(JNIEnv* env,
jobject clazz, DisplayList* displayList) {
return displayList->getLeft();
}
static jfloat android_view_GLES20DisplayList_getTop(JNIEnv* env,
jobject clazz, DisplayList* displayList) {
return displayList->getTop();
}
static jfloat android_view_GLES20DisplayList_getRight(JNIEnv* env,
jobject clazz, DisplayList* displayList) {
return displayList->getRight();
}
static jfloat android_view_GLES20DisplayList_getBottom(JNIEnv* env,
jobject clazz, DisplayList* displayList) {
return displayList->getBottom();
}
static jfloat android_view_GLES20DisplayList_getCameraDistance(JNIEnv* env,
jobject clazz, DisplayList* displayList) {
return displayList->getCameraDistance();
}
static jfloat android_view_GLES20DisplayList_getScaleX(JNIEnv* env,
jobject clazz, DisplayList* displayList) {
return displayList->getScaleX();
}
static jfloat android_view_GLES20DisplayList_getScaleY(JNIEnv* env,
jobject clazz, DisplayList* displayList) {
return displayList->getScaleY();
}
static jfloat android_view_GLES20DisplayList_getTranslationX(JNIEnv* env,
jobject clazz, DisplayList* displayList) {
return displayList->getTranslationX();
}
static jfloat android_view_GLES20DisplayList_getTranslationY(JNIEnv* env,
jobject clazz, DisplayList* displayList) {
return displayList->getTranslationY();
}
static jfloat android_view_GLES20DisplayList_getRotation(JNIEnv* env,
jobject clazz, DisplayList* displayList) {
return displayList->getRotation();
}
static jfloat android_view_GLES20DisplayList_getRotationX(JNIEnv* env,
jobject clazz, DisplayList* displayList) {
return displayList->getRotationX();
}
static jfloat android_view_GLES20DisplayList_getRotationY(JNIEnv* env,
jobject clazz, DisplayList* displayList) {
return displayList->getRotationY();
}
static jfloat android_view_GLES20DisplayList_getPivotX(JNIEnv* env,
jobject clazz, DisplayList* displayList) {
return displayList->getPivotX();
}
static jfloat android_view_GLES20DisplayList_getPivotY(JNIEnv* env,
jobject clazz, DisplayList* displayList) {
return displayList->getPivotY();
}
#endif // USE_OPENGL_RENDERER
// ----------------------------------------------------------------------------
@ -190,6 +299,11 @@ const char* const kClassPathName = "android/view/GLES20DisplayList";
static JNINativeMethod gMethods[] = {
#ifdef USE_OPENGL_RENDERER
{ "nDestroyDisplayList", "(I)V", (void*) android_view_GLES20DisplayList_destroyDisplayList },
{ "nGetDisplayListSize", "(I)I", (void*) android_view_GLES20DisplayList_getDisplayListSize },
{ "nSetDisplayListName", "(ILjava/lang/String;)V",
(void*) android_view_GLES20DisplayList_setDisplayListName },
{ "nReset", "(I)V", (void*) android_view_GLES20DisplayList_reset },
{ "nSetCaching", "(IZ)V", (void*) android_view_GLES20DisplayList_setCaching },
{ "nSetStaticMatrix", "(II)V", (void*) android_view_GLES20DisplayList_setStaticMatrix },
@ -214,12 +328,29 @@ static JNINativeMethod gMethods[] = {
{ "nSetTop", "(II)V", (void*) android_view_GLES20DisplayList_setTop },
{ "nSetRight", "(II)V", (void*) android_view_GLES20DisplayList_setRight },
{ "nSetBottom", "(II)V", (void*) android_view_GLES20DisplayList_setBottom },
{ "nSetLeftTop", "(III)V", (void*) android_view_GLES20DisplayList_setLeftTop },
{ "nSetLeftTopRightBottom","(IIIII)V",
(void*) android_view_GLES20DisplayList_setLeftTopRightBottom },
{ "nOffsetLeftRight", "(II)V", (void*) android_view_GLES20DisplayList_offsetLeftRight },
{ "nOffsetTopBottom", "(II)V", (void*) android_view_GLES20DisplayList_offsetTopBottom },
{ "nOffsetLeftAndRight", "(IF)V", (void*) android_view_GLES20DisplayList_offsetLeftAndRight },
{ "nOffsetTopAndBottom", "(IF)V", (void*) android_view_GLES20DisplayList_offsetTopAndBottom },
{ "nGetMatrix", "(II)V", (void*) android_view_GLES20DisplayList_getMatrix },
{ "nHasOverlappingRendering", "(I)Z", (void*) android_view_GLES20DisplayList_hasOverlappingRendering },
{ "nGetAlpha", "(I)F", (void*) android_view_GLES20DisplayList_getAlpha },
{ "nGetLeft", "(I)F", (void*) android_view_GLES20DisplayList_getLeft },
{ "nGetTop", "(I)F", (void*) android_view_GLES20DisplayList_getTop },
{ "nGetRight", "(I)F", (void*) android_view_GLES20DisplayList_getRight },
{ "nGetBottom", "(I)F", (void*) android_view_GLES20DisplayList_getBottom },
{ "nGetCameraDistance", "(I)F", (void*) android_view_GLES20DisplayList_getCameraDistance },
{ "nGetScaleX", "(I)F", (void*) android_view_GLES20DisplayList_getScaleX },
{ "nGetScaleY", "(I)F", (void*) android_view_GLES20DisplayList_getScaleY },
{ "nGetTranslationX", "(I)F", (void*) android_view_GLES20DisplayList_getTranslationX },
{ "nGetTranslationY", "(I)F", (void*) android_view_GLES20DisplayList_getTranslationY },
{ "nGetRotation", "(I)F", (void*) android_view_GLES20DisplayList_getRotation },
{ "nGetRotationX", "(I)F", (void*) android_view_GLES20DisplayList_getRotationX },
{ "nGetRotationY", "(I)F", (void*) android_view_GLES20DisplayList_getRotationY },
{ "nGetPivotX", "(I)F", (void*) android_view_GLES20DisplayList_getPivotX },
{ "nGetPivotY", "(I)F", (void*) android_view_GLES20DisplayList_getPivotY },
#endif
};

View File

@ -263,6 +263,16 @@ void DisplayList::output(uint32_t level) {
ALOGD("%*sDone (%p, %s)", level * 2, "", this, mName.string());
}
float DisplayList::getPivotX() {
updateMatrix();
return mPivotX;
}
float DisplayList::getPivotY() {
updateMatrix();
return mPivotY;
}
void DisplayList::updateMatrix() {
if (mMatrixDirty) {
if (!mTransformMatrix) {

View File

@ -105,6 +105,10 @@ public:
}
}
const char* getName() const {
return mName.string();
}
void setClipChildren(bool clipChildren) {
mClipChildren = clipChildren;
}
@ -114,6 +118,11 @@ public:
mStaticMatrix = new SkMatrix(*matrix);
}
// Can return NULL
SkMatrix* getStaticMatrix() {
return mStaticMatrix;
}
void setAnimationMatrix(SkMatrix* matrix) {
delete mAnimationMatrix;
if (matrix) {
@ -131,10 +140,18 @@ public:
}
}
float getAlpha() const {
return mAlpha;
}
void setHasOverlappingRendering(bool hasOverlappingRendering) {
mHasOverlappingRendering = hasOverlappingRendering;
}
bool hasOverlappingRendering() const {
return mHasOverlappingRendering;
}
void setTranslationX(float translationX) {
if (translationX != mTranslationX) {
mTranslationX = translationX;
@ -147,6 +164,10 @@ public:
}
}
float getTranslationX() const {
return mTranslationX;
}
void setTranslationY(float translationY) {
if (translationY != mTranslationY) {
mTranslationY = translationY;
@ -159,6 +180,10 @@ public:
}
}
float getTranslationY() const {
return mTranslationY;
}
void setRotation(float rotation) {
if (rotation != mRotation) {
mRotation = rotation;
@ -171,6 +196,10 @@ public:
}
}
float getRotation() const {
return mRotation;
}
void setRotationX(float rotationX) {
if (rotationX != mRotationX) {
mRotationX = rotationX;
@ -183,6 +212,10 @@ public:
}
}
float getRotationX() const {
return mRotationX;
}
void setRotationY(float rotationY) {
if (rotationY != mRotationY) {
mRotationY = rotationY;
@ -195,6 +228,10 @@ public:
}
}
float getRotationY() const {
return mRotationY;
}
void setScaleX(float scaleX) {
if (scaleX != mScaleX) {
mScaleX = scaleX;
@ -207,6 +244,10 @@ public:
}
}
float getScaleX() const {
return mScaleX;
}
void setScaleY(float scaleY) {
if (scaleY != mScaleY) {
mScaleY = scaleY;
@ -219,6 +260,10 @@ public:
}
}
float getScaleY() const {
return mScaleY;
}
void setPivotX(float pivotX) {
mPivotX = pivotX;
mMatrixDirty = true;
@ -230,6 +275,8 @@ public:
mPivotExplicitlySet = true;
}
ANDROID_API float getPivotX();
void setPivotY(float pivotY) {
mPivotY = pivotY;
mMatrixDirty = true;
@ -241,6 +288,8 @@ public:
mPivotExplicitlySet = true;
}
ANDROID_API float getPivotY();
void setCameraDistance(float distance) {
if (distance != mCameraDistance) {
mCameraDistance = distance;
@ -253,6 +302,10 @@ public:
}
}
float getCameraDistance() const {
return mCameraDistance;
}
void setLeft(int left) {
if (left != mLeft) {
mLeft = left;
@ -263,6 +316,10 @@ public:
}
}
float getLeft() const {
return mLeft;
}
void setTop(int top) {
if (top != mTop) {
mTop = top;
@ -273,6 +330,10 @@ public:
}
}
float getTop() const {
return mTop;
}
void setRight(int right) {
if (right != mRight) {
mRight = right;
@ -283,6 +344,10 @@ public:
}
}
float getRight() const {
return mRight;
}
void setBottom(int bottom) {
if (bottom != mBottom) {
mBottom = bottom;
@ -293,6 +358,10 @@ public:
}
}
float getBottom() const {
return mBottom;
}
void setLeftTop(int left, int top) {
if (left != mLeft || top != mTop) {
mLeft = left;
@ -319,7 +388,7 @@ public:
}
}
void offsetLeftRight(int offset) {
void offsetLeftRight(float offset) {
if (offset != 0) {
mLeft += offset;
mRight += offset;
@ -329,7 +398,7 @@ public:
}
}
void offsetTopBottom(int offset) {
void offsetTopBottom(float offset) {
if (offset != 0) {
mTop += offset;
mBottom += offset;

View File

@ -280,7 +280,7 @@ void OpenGLRenderer::startTiling(const sp<Snapshot>& s, bool opaque) {
void OpenGLRenderer::startTiling(const Rect& clip, int windowHeight, bool opaque) {
if (!mSuppressTiling) {
mCaches.startTiling(clip.left, windowHeight - clip.bottom,
clip.right - clip.left, clip.bottom - clip.top, opaque);
clip.right - clip.left, clip.bottom - clip.top, opaque);
}
}