diff --git a/core/java/android/view/GLES20Canvas.java b/core/java/android/view/GLES20Canvas.java index 9c44737d05b3b..7ff8d0914e567 100644 --- a/core/java/android/view/GLES20Canvas.java +++ b/core/java/android/view/GLES20Canvas.java @@ -937,6 +937,8 @@ class GLES20Canvas extends HardwareCanvas { @Override public void drawLines(float[] pts, int offset, int count, Paint paint) { + if (count < 4) return; + if ((offset | count) < 0 || offset + count > pts.length) { throw new IllegalArgumentException("The lines array must contain 4 elements per line."); } @@ -1060,6 +1062,8 @@ class GLES20Canvas extends HardwareCanvas { @Override public void drawPoints(float[] pts, int offset, int count, Paint paint) { + if (count < 2) return; + int modifiers = setupModifiers(paint, MODIFIER_COLOR_FILTER | MODIFIER_SHADER); try { nDrawPoints(mRenderer, pts, offset, count, paint.mNativePaint); diff --git a/graphics/java/android/graphics/Canvas.java b/graphics/java/android/graphics/Canvas.java index 8cbf299ba31d4..e94ddae95e6c1 100644 --- a/graphics/java/android/graphics/Canvas.java +++ b/graphics/java/android/graphics/Canvas.java @@ -1199,7 +1199,7 @@ public class Canvas { * meshHeight+1 vertices down. The verts array is accessed in row-major * order, so that the first meshWidth+1 vertices are distributed across the * top of the bitmap from left to right. A more general version of this - * methid is drawVertices(). + * method is drawVertices(). * * @param bitmap The bitmap to draw using the mesh * @param meshWidth The number of columns in the mesh. Nothing is drawn if @@ -1208,7 +1208,7 @@ public class Canvas { * this is 0 * @param verts Array of x,y pairs, specifying where the mesh should be * drawn. There must be at least - * (meshWidth+1) * (meshHeight+1) * 2 + meshOffset values + * (meshWidth+1) * (meshHeight+1) * 2 + vertOffset values * in the array * @param vertOffset Number of verts elements to skip before drawing * @param colors May be null. Specifies a color at each vertex, which is diff --git a/libs/hwui/DisplayList.cpp b/libs/hwui/DisplayList.cpp index 6fab8dab11fd3..398f719fcf6f9 100644 --- a/libs/hwui/DisplayList.cpp +++ b/libs/hwui/DisplayList.cpp @@ -436,13 +436,8 @@ status_t DisplayList::replay(OpenGLRenderer& renderer, Rect& dirty, int32_t flag Caches::getInstance().eventMark(strlen(op->name()), op->name()); #endif - if (deferredList) { - drawGlStatus |= op->replay(renderer, dirty, flags, - saveCount, level, mCaching, mMultipliedAlpha, *deferredList); - } else { - drawGlStatus |= op->replay(renderer, dirty, flags, - saveCount, level, mCaching, mMultipliedAlpha); - } + drawGlStatus |= op->replay(renderer, dirty, flags, + saveCount, level, mCaching, mMultipliedAlpha, deferredList); logBuffer.writeCommand(level, op->name()); } diff --git a/libs/hwui/DisplayListOp.h b/libs/hwui/DisplayListOp.h index 8e80647b5c136..1bae0ff1e9609 100644 --- a/libs/hwui/DisplayListOp.h +++ b/libs/hwui/DisplayListOp.h @@ -74,14 +74,11 @@ public: kOpLogFlag_JSON = 0x2 // TODO: add? }; - virtual status_t replay(OpenGLRenderer& renderer, Rect& dirty, int32_t flags, int saveCount, - uint32_t level, bool caching, int multipliedAlpha) = 0; - - // same as replay above, but draw operations will defer into the deferredList if possible - // NOTE: colorfilters, paintfilters, shaders, shadow, and complex clips prevent deferral + // If a DeferredDisplayList is supplied, DrawOps will be stored until the list is flushed + // NOTE: complex clips and layers prevent deferral virtual status_t replay(OpenGLRenderer& renderer, Rect& dirty, int32_t flags, int saveCount, uint32_t level, bool caching, int multipliedAlpha, - DeferredDisplayList& deferredList) = 0; + DeferredDisplayList* deferredList) = 0; virtual void output(int level, uint32_t flags = 0) = 0; @@ -96,22 +93,16 @@ public: virtual ~StateOp() {} - virtual status_t replay(OpenGLRenderer& renderer, Rect& dirty, int32_t flags, int saveCount, - uint32_t level, bool caching, int multipliedAlpha) { - applyState(renderer, saveCount); - return DrawGlInfo::kStatusDone; - } - /** * State operations are applied directly to the renderer, but can cause the deferred drawing op * list to flush */ virtual status_t replay(OpenGLRenderer& renderer, Rect& dirty, int32_t flags, int saveCount, - uint32_t level, bool caching, int multipliedAlpha, DeferredDisplayList& deferredList) { + uint32_t level, bool caching, int multipliedAlpha, DeferredDisplayList* deferredList) { status_t status = DrawGlInfo::kStatusDone; - if (requiresDrawOpFlush()) { + if (deferredList && requiresDrawOpFlush()) { // will be setting renderer state that affects ops in deferredList, so flush list first - status |= deferredList.flush(renderer, dirty, flags, level); + status |= deferredList->flush(renderer, dirty, flags, level); } applyState(renderer, saveCount); return status; @@ -131,23 +122,14 @@ public: DrawOp(SkPaint* paint) : mPaint(paint), mQuickRejected(false) {} - virtual status_t replay(OpenGLRenderer& renderer, Rect& dirty, int32_t flags, int saveCount, - uint32_t level, bool caching, int multipliedAlpha) { - if (mQuickRejected && CC_LIKELY(flags & DisplayList::kReplayFlag_ClipChildren)) { - return DrawGlInfo::kStatusDone; - } - - return applyDraw(renderer, dirty, level, caching, multipliedAlpha); - } - /** Draw operations are stored in the deferredList with information necessary for playback */ virtual status_t replay(OpenGLRenderer& renderer, Rect& dirty, int32_t flags, int saveCount, - uint32_t level, bool caching, int multipliedAlpha, DeferredDisplayList& deferredList) { + uint32_t level, bool caching, int multipliedAlpha, DeferredDisplayList* deferredList) { if (mQuickRejected && CC_LIKELY(flags & DisplayList::kReplayFlag_ClipChildren)) { return DrawGlInfo::kStatusDone; } - if (renderer.disallowDeferral()) { + if (!deferredList || renderer.disallowDeferral()) { // dispatch draw immediately, since the renderer's state is too complex for deferral return applyDraw(renderer, dirty, level, caching, multipliedAlpha); } @@ -161,7 +143,7 @@ public: if (!renderer.storeDisplayState(state)) { // op wasn't quick-rejected, so defer - deferredList.add(this, renderer.disallowReorder()); + deferredList->add(this, renderer.disallowReorder()); } return DrawGlInfo::kStatusDone; @@ -184,7 +166,6 @@ public: float strokeWidthOutset() { return mPaint->getStrokeWidth() * 0.5f; } -public: /** * Stores the relevant canvas state of the object between deferral and replay (if the canvas * state supports being stored) See OpenGLRenderer::simpleClipAndState() @@ -204,7 +185,20 @@ public: DrawBoundedOp(float left, float top, float right, float bottom, SkPaint* paint) : DrawOp(paint), mLocalBounds(left, top, right, bottom) {} - // default constructor for area, to be overridden in child constructor body + // Calculates bounds as smallest rect encompassing all points + // NOTE: requires at least 1 vertex, and doesn't account for stroke size (should be handled in + // subclass' constructor) + DrawBoundedOp(const float* points, int count, SkPaint* paint) + : DrawOp(paint), mLocalBounds(points[0], points[1], points[0], points[1]) { + for (int i = 2; i < count; i += 2) { + mLocalBounds.left = fminf(mLocalBounds.left, points[i]); + mLocalBounds.right = fmaxf(mLocalBounds.right, points[i]); + mLocalBounds.top = fminf(mLocalBounds.top, points[i + 1]); + mLocalBounds.bottom = fmaxf(mLocalBounds.bottom, points[i + 1]); + } + } + + // default empty constructor for bounds, to be overridden in child constructor body DrawBoundedOp(SkPaint* paint) : DrawOp(paint) {} @@ -740,11 +734,12 @@ public: } }; -class DrawBitmapMeshOp : public DrawOp { +class DrawBitmapMeshOp : public DrawBoundedOp { public: DrawBitmapMeshOp(SkBitmap* bitmap, int meshWidth, int meshHeight, float* vertices, int* colors, SkPaint* paint) - : DrawOp(paint), mBitmap(bitmap), mMeshWidth(meshWidth), mMeshHeight(meshHeight), + : DrawBoundedOp(vertices, 2 * (meshWidth + 1) * (meshHeight + 1), paint), + mBitmap(bitmap), mMeshWidth(meshWidth), mMeshHeight(meshHeight), mVertices(vertices), mColors(colors) {} virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, uint32_t level, @@ -873,10 +868,11 @@ public: virtual const char* name() { return "DrawRect"; } }; -class DrawRectsOp : public DrawOp { +class DrawRectsOp : public DrawBoundedOp { public: DrawRectsOp(const float* rects, int count, SkPaint* paint) - : DrawOp(paint), mRects(rects), mCount(count) {} + : DrawBoundedOp(rects, count, paint), + mRects(rects), mCount(count) {} virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, uint32_t level, bool caching, int multipliedAlpha) { @@ -1022,13 +1018,8 @@ private: class DrawLinesOp : public DrawBoundedOp { public: DrawLinesOp(float* points, int count, SkPaint* paint) - : DrawBoundedOp(paint), mPoints(points), mCount(count) { - for (int i = 0; i < count; i += 2) { - mLocalBounds.left = fminf(mLocalBounds.left, points[i]); - mLocalBounds.right = fmaxf(mLocalBounds.right, points[i]); - mLocalBounds.top = fminf(mLocalBounds.top, points[i+1]); - mLocalBounds.bottom = fmaxf(mLocalBounds.bottom, points[i+1]); - } + : DrawBoundedOp(points, count, paint), + mPoints(points), mCount(count) { mLocalBounds.outset(strokeWidthOutset()); } @@ -1199,26 +1190,23 @@ private: Functor* mFunctor; }; -class DrawDisplayListOp : public DrawOp { +class DrawDisplayListOp : public DrawBoundedOp { public: DrawDisplayListOp(DisplayList* displayList, int flags) - : DrawOp(0), mDisplayList(displayList), mFlags(flags) {} + : DrawBoundedOp(0, 0, displayList->getWidth(), displayList->getHeight(), 0), + mDisplayList(displayList), mFlags(flags) {} virtual status_t replay(OpenGLRenderer& renderer, Rect& dirty, int32_t flags, int saveCount, - uint32_t level, bool caching, int multipliedAlpha, DeferredDisplayList& deferredList) { + uint32_t level, bool caching, int multipliedAlpha, DeferredDisplayList* deferredList) { if (mDisplayList && mDisplayList->isRenderable()) { - return mDisplayList->replay(renderer, dirty, mFlags, level + 1, &deferredList); + return mDisplayList->replay(renderer, dirty, mFlags, level + 1, deferredList); } return DrawGlInfo::kStatusDone; } + // NOT USED, since replay is overridden virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, uint32_t level, - bool caching, int multipliedAlpha) { - if (mDisplayList && mDisplayList->isRenderable()) { - return mDisplayList->replay(renderer, dirty, mFlags, level + 1); - } - return DrawGlInfo::kStatusDone; - } + bool caching, int multipliedAlpha) { return DrawGlInfo::kStatusDone; } virtual void output(int level, uint32_t flags) { OP_LOG("Draw Display List %p, flags %#x", mDisplayList, mFlags); diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp index e5fd7b9f03680..6b614a7fd87c7 100644 --- a/libs/hwui/OpenGLRenderer.cpp +++ b/libs/hwui/OpenGLRenderer.cpp @@ -1235,6 +1235,8 @@ bool OpenGLRenderer::storeDisplayState(DeferredDisplayState& state) { // quick rejected return true; } + } else { + state.mBounds.set(currentClip); } state.mClip.set(currentClip);