diff options
-rw-r--r-- | core/java/android/view/GLES20Canvas.java | 24 | ||||
-rw-r--r-- | core/jni/android_view_GLES20Canvas.cpp | 15 | ||||
-rw-r--r-- | graphics/java/android/graphics/Region.java | 6 | ||||
-rw-r--r-- | libs/hwui/Matrix.cpp | 19 | ||||
-rw-r--r-- | libs/hwui/Matrix.h | 2 | ||||
-rw-r--r-- | libs/hwui/OpenGLRenderer.cpp | 50 | ||||
-rw-r--r-- | libs/hwui/OpenGLRenderer.h | 3 | ||||
-rw-r--r-- | libs/hwui/Rect.h | 19 | ||||
-rw-r--r-- | libs/hwui/Snapshot.h | 79 |
9 files changed, 130 insertions, 87 deletions
diff --git a/core/java/android/view/GLES20Canvas.java b/core/java/android/view/GLES20Canvas.java index a2ab8bded22a..676aae3aa513 100644 --- a/core/java/android/view/GLES20Canvas.java +++ b/core/java/android/view/GLES20Canvas.java @@ -149,43 +149,44 @@ class GLES20Canvas extends Canvas { @Override public boolean clipRect(float left, float top, float right, float bottom) { - return nClipRect(mRenderer, left, top, right, bottom); + return nClipRect(mRenderer, left, top, right, bottom, Region.Op.INTERSECT.nativeInt); } - private native boolean nClipRect(int renderer, float left, float top, float right, float bottom); + private native boolean nClipRect(int renderer, float left, float top, + float right, float bottom, int op); @Override public boolean clipRect(float left, float top, float right, float bottom, Region.Op op) { - throw new UnsupportedOperationException(); + return nClipRect(mRenderer, left, top, right, bottom, op.nativeInt); } @Override public boolean clipRect(int left, int top, int right, int bottom) { - return nClipRect(mRenderer, left, top, right, bottom); + return nClipRect(mRenderer, left, top, right, bottom, Region.Op.INTERSECT.nativeInt); } - private native boolean nClipRect(int renderer, int left, int top, int right, int bottom); + private native boolean nClipRect(int renderer, int left, int top, int right, int bottom, int op); @Override public boolean clipRect(Rect rect) { - return clipRect(rect.left, rect.top, rect.right, rect.bottom); + return nClipRect(mRenderer, rect.left, rect.top, rect.right, rect.bottom, + Region.Op.INTERSECT.nativeInt); } @Override public boolean clipRect(Rect rect, Region.Op op) { - // TODO: Implement - throw new UnsupportedOperationException(); + return nClipRect(mRenderer, rect.left, rect.top, rect.right, rect.bottom, op.nativeInt); } @Override public boolean clipRect(RectF rect) { - return clipRect(rect.left, rect.top, rect.right, rect.bottom); + return nClipRect(mRenderer, rect.left, rect.top, rect.right, rect.bottom, + Region.Op.INTERSECT.nativeInt); } @Override public boolean clipRect(RectF rect, Region.Op op) { - // TODO: Implement - throw new UnsupportedOperationException(); + return nClipRect(mRenderer, rect.left, rect.top, rect.right, rect.bottom, op.nativeInt); } @Override @@ -347,7 +348,6 @@ class GLES20Canvas extends Canvas { @Override public void setDrawFilter(DrawFilter filter) { - // Don't crash, but ignore the draw filter // TODO: Implement PaintDrawFilter mFilter = filter; } diff --git a/core/jni/android_view_GLES20Canvas.cpp b/core/jni/android_view_GLES20Canvas.cpp index dbf482e6c0dd..e5aa5dd07435 100644 --- a/core/jni/android_view_GLES20Canvas.cpp +++ b/core/jni/android_view_GLES20Canvas.cpp @@ -23,6 +23,7 @@ #include <SkCanvas.h> #include <SkMatrix.h> #include <SkPaint.h> +#include <SkRegion.h> #include <SkXfermode.h> #include <OpenGLRenderer.h> @@ -120,13 +121,15 @@ static bool android_view_GLES20Canvas_quickReject(JNIEnv* env, jobject canvas, } static bool android_view_GLES20Canvas_clipRectF(JNIEnv* env, jobject canvas, - OpenGLRenderer* renderer, jfloat left, jfloat top, jfloat right, jfloat bottom) { - return renderer->clipRect(left, top, right, bottom); + OpenGLRenderer* renderer, jfloat left, jfloat top, jfloat right, jfloat bottom, + SkRegion::Op op) { + return renderer->clipRect(left, top, right, bottom, op); } static bool android_view_GLES20Canvas_clipRect(JNIEnv* env, jobject canvas, - OpenGLRenderer* renderer, jint left, jint top, jint right, jint bottom) { - return renderer->clipRect(float(left), float(top), float(right), float(bottom)); + OpenGLRenderer* renderer, jint left, jint top, jint right, jint bottom, + SkRegion::Op op) { + return renderer->clipRect(float(left), float(top), float(right), float(bottom), op); } static bool android_view_GLES20Canvas_getClipBounds(JNIEnv* env, jobject canvas, @@ -257,8 +260,8 @@ static JNINativeMethod gMethods[] = { { "nSaveLayerAlpha", "(IFFFFII)I", (void*) android_view_GLES20Canvas_saveLayerAlpha }, { "nQuickReject", "(IFFFFI)Z", (void*) android_view_GLES20Canvas_quickReject }, - { "nClipRect", "(IFFFF)Z", (void*) android_view_GLES20Canvas_clipRectF }, - { "nClipRect", "(IIIII)Z", (void*) android_view_GLES20Canvas_clipRect }, + { "nClipRect", "(IFFFFI)Z", (void*) android_view_GLES20Canvas_clipRectF }, + { "nClipRect", "(IIIIII)Z", (void*) android_view_GLES20Canvas_clipRect }, { "nTranslate", "(IFF)V", (void*) android_view_GLES20Canvas_translate }, { "nRotate", "(IF)V", (void*) android_view_GLES20Canvas_rotate }, diff --git a/graphics/java/android/graphics/Region.java b/graphics/java/android/graphics/Region.java index 2b080aaa6be5..489ef83811f5 100644 --- a/graphics/java/android/graphics/Region.java +++ b/graphics/java/android/graphics/Region.java @@ -33,7 +33,11 @@ public class Region implements Parcelable { Op(int nativeInt) { this.nativeInt = nativeInt; } - final int nativeInt; + + /** + * @hide + */ + public final int nativeInt; } /** Create an empty region diff --git a/libs/hwui/Matrix.cpp b/libs/hwui/Matrix.cpp index 877d3bbfb2bd..b45920242b1f 100644 --- a/libs/hwui/Matrix.cpp +++ b/libs/hwui/Matrix.cpp @@ -93,6 +93,25 @@ void Matrix4::copyTo(SkMatrix& v) const { v.set(SkMatrix::kMPersp2, data[15]); } +void Matrix4::loadInverse(const Matrix4& v) { + double scale = 1.0 / + (v.data[0] * ((double) v.data[5] * v.data[15] - (double) v.data[13] * v.data[7]) + + v.data[4] * ((double) v.data[13] * v.data[3] - (double) v.data[1] * v.data[15]) + + v.data[12] * ((double) v.data[1] * v.data[7] - (double) v.data[5] * v.data[3])); + + data[0] = (v.data[5] * v.data[15] - v.data[13] * v.data[7]) * scale; + data[4] = (v.data[12] * v.data[7] - v.data[4] * v.data[15]) * scale; + data[12] = (v.data[4] * v.data[13] - v.data[12] * v.data[5]) * scale; + + data[1] = (v.data[13] * v.data[3] - v.data[1] * v.data[15]) * scale; + data[5] = (v.data[0] * v.data[15] - v.data[12] * v.data[3]) * scale; + data[13] = (v.data[12] * v.data[1] - v.data[0] * v.data[13]) * scale; + + data[3] = (v.data[1] * v.data[7] - v.data[5] * v.data[3]) * scale; + data[7] = (v.data[4] * v.data[3] - v.data[0] * v.data[7]) * scale; + data[15] = (v.data[0] * v.data[5] - v.data[4] * v.data[1]) * scale; +} + void Matrix4::copyTo(float* v) const { memcpy(v, data, sizeof(data)); } diff --git a/libs/hwui/Matrix.h b/libs/hwui/Matrix.h index ba5be03469c5..b8a4da77619c 100644 --- a/libs/hwui/Matrix.h +++ b/libs/hwui/Matrix.h @@ -54,6 +54,8 @@ public: void load(const Matrix4& v); void load(const SkMatrix& v); + void loadInverse(const Matrix4& v); + void loadTranslate(float x, float y, float z); void loadScale(float sx, float sy, float sz); void loadRotate(float angle, float x, float y, float z); diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp index decfecfcbe4e..d950ffac7f4e 100644 --- a/libs/hwui/OpenGLRenderer.cpp +++ b/libs/hwui/OpenGLRenderer.cpp @@ -244,7 +244,7 @@ void OpenGLRenderer::composeLayer(sp<Snapshot> current, sp<Snapshot> previous) { glBindFramebuffer(GL_FRAMEBUFFER, previous->fbo); // Restore the clip from the previous snapshot - const Rect& clip = previous->getMappedClip(); + const Rect& clip = previous->clipRect; glScissor(clip.left, mHeight - clip.bottom, clip.getWidth(), clip.getHeight()); Layer* layer = current->layer; @@ -339,12 +339,11 @@ bool OpenGLRenderer::createLayer(sp<Snapshot> snapshot, float left, float top, saveSnapshot(); // TODO: This doesn't preserve other transformations (check Skia first) mSnapshot->transform.loadTranslate(-left, -top, 0.0f); - mSnapshot->setClip(left, top, right, bottom); + mSnapshot->setClip(0.0f, 0.0f, right - left, bottom - top); mSnapshot->height = bottom - top; setScissorFromClip(); - mSnapshot->flags = Snapshot::kFlagDirtyTransform | Snapshot::kFlagDirtyOrtho | - Snapshot::kFlagClipSet; + mSnapshot->flags = Snapshot::kFlagDirtyOrtho | Snapshot::kFlagClipSet; mSnapshot->orthoMatrix.load(mOrthoMatrix); // Change the ortho projection @@ -359,22 +358,18 @@ bool OpenGLRenderer::createLayer(sp<Snapshot> snapshot, float left, float top, void OpenGLRenderer::translate(float dx, float dy) { mSnapshot->transform.translate(dx, dy, 0.0f); - mSnapshot->flags |= Snapshot::kFlagDirtyTransform; } void OpenGLRenderer::rotate(float degrees) { mSnapshot->transform.rotate(degrees, 0.0f, 0.0f, 1.0f); - mSnapshot->flags |= Snapshot::kFlagDirtyTransform; } void OpenGLRenderer::scale(float sx, float sy) { mSnapshot->transform.scale(sx, sy, 1.0f); - mSnapshot->flags |= Snapshot::kFlagDirtyTransform; } void OpenGLRenderer::setMatrix(SkMatrix* matrix) { mSnapshot->transform.load(*matrix); - mSnapshot->flags |= Snapshot::kFlagDirtyTransform; } void OpenGLRenderer::getMatrix(SkMatrix* matrix) { @@ -384,7 +379,6 @@ void OpenGLRenderer::getMatrix(SkMatrix* matrix) { void OpenGLRenderer::concatMatrix(SkMatrix* matrix) { mat4 m(*matrix); mSnapshot->transform.multiply(m); - mSnapshot->flags |= Snapshot::kFlagDirtyTransform; } /////////////////////////////////////////////////////////////////////////////// @@ -392,38 +386,26 @@ void OpenGLRenderer::concatMatrix(SkMatrix* matrix) { /////////////////////////////////////////////////////////////////////////////// void OpenGLRenderer::setScissorFromClip() { - const Rect& clip = mSnapshot->getMappedClip(); + const Rect& clip = mSnapshot->clipRect; glScissor(clip.left, mSnapshot->height - clip.bottom, clip.getWidth(), clip.getHeight()); } const Rect& OpenGLRenderer::getClipBounds() { - return mSnapshot->clipRect; + return mSnapshot->getLocalClip(); } bool OpenGLRenderer::quickReject(float left, float top, float right, float bottom) { - /* - * The documentation of quickReject() indicates that the specified rect - * is transformed before being compared to the clip rect. However, the - * clip rect is not stored transformed in the snapshot and can thus be - * compared directly - * - * The following code can be used instead to performed a mapped comparison: - * - * mSnapshot->transform.mapRect(r); - * const Rect& clip = mSnapshot->getMappedClip(); - * return !clip.intersects(r); - */ Rect r(left, top, right, bottom); + mSnapshot->transform.mapRect(r); return !mSnapshot->clipRect.intersects(r); } -bool OpenGLRenderer::clipRect(float left, float top, float right, float bottom) { - bool clipped = mSnapshot->clip(left, top, right, bottom); +bool OpenGLRenderer::clipRect(float left, float top, float right, float bottom, SkRegion::Op op) { + bool clipped = mSnapshot->clip(left, top, right, bottom, op); if (clipped) { - mSnapshot->flags |= Snapshot::kFlagClipSet; setScissorFromClip(); } - return clipped; + return !mSnapshot->clipRect.isEmpty(); } /////////////////////////////////////////////////////////////////////////////// @@ -504,7 +486,7 @@ void OpenGLRenderer::drawPatch(SkBitmap* bitmap, Res_png_9patch* patch, } void OpenGLRenderer::drawColor(int color, SkXfermode::Mode mode) { - const Rect& clip = mSnapshot->getMappedClip(); + const Rect& clip = mSnapshot->clipRect; drawColorRect(clip.left, clip.top, clip.right, clip.bottom, color, mode, true); } @@ -584,22 +566,20 @@ void OpenGLRenderer::drawColorRect(float left, float top, float right, float bot mModelView.loadTranslate(left, top, 0.0f); mModelView.scale(right - left, bottom - top, 1.0f); - // TODO: Pick the program matching the current shader - sp<DrawColorProgram> program = mDrawColorProgram; - if (!useProgram(program)) { + if (!useProgram(mDrawColorProgram)) { const GLvoid* p = &gDrawColorVertices[0].position[0]; - glVertexAttribPointer(program->position, 2, GL_FLOAT, GL_FALSE, + glVertexAttribPointer(mDrawColorProgram->position, 2, GL_FLOAT, GL_FALSE, gDrawColorVertexStride, p); } if (!ignoreTransform) { - program->set(mOrthoMatrix, mModelView, mSnapshot->transform); + mDrawColorProgram->set(mOrthoMatrix, mModelView, mSnapshot->transform); } else { mat4 identity; - program->set(mOrthoMatrix, mModelView, identity); + mDrawColorProgram->set(mOrthoMatrix, mModelView, identity); } - glUniform4f(program->color, r, g, b, a); + glUniform4f(mDrawColorProgram->color, r, g, b, a); glDrawArrays(GL_TRIANGLE_STRIP, 0, gDrawColorVertexCount); } diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h index 2a964323a8b3..566722966646 100644 --- a/libs/hwui/OpenGLRenderer.h +++ b/libs/hwui/OpenGLRenderer.h @@ -23,6 +23,7 @@ #include <SkBitmap.h> #include <SkMatrix.h> #include <SkPaint.h> +#include <SkRegion.h> #include <SkShader.h> #include <SkXfermode.h> @@ -88,7 +89,7 @@ public: const Rect& getClipBounds(); bool quickReject(float left, float top, float right, float bottom); - bool clipRect(float left, float top, float right, float bottom); + bool clipRect(float left, float top, float right, float bottom, SkRegion::Op op); void drawBitmap(SkBitmap* bitmap, float left, float top, const SkPaint* paint); void drawBitmap(SkBitmap* bitmap, const SkMatrix* matrix, const SkPaint* paint); diff --git a/libs/hwui/Rect.h b/libs/hwui/Rect.h index ad57550563f4..7be0c340399d 100644 --- a/libs/hwui/Rect.h +++ b/libs/hwui/Rect.h @@ -129,6 +129,25 @@ struct Rect { return intersect(r.left, r.top, r.right, r.bottom); } + bool unionWith(const Rect& r) { + if (r.left < r.right && r.top < r.bottom) { + if (left < right && top < bottom) { + if (left > r.left) left = r.left; + if (top > r.top) top = r.top; + if (right < r.right) right = r.right; + if (bottom < r.bottom) bottom = r.bottom; + return true; + } else { + left = r.left; + top = r.top; + right = r.right; + bottom = r.bottom; + return true; + } + } + return false; + } + void dump() const { LOGD("Rect[l=%f t=%f r=%f b=%f]", left, top, right, bottom); } diff --git a/libs/hwui/Snapshot.h b/libs/hwui/Snapshot.h index 32fee324f488..96dfab97cb86 100644 --- a/libs/hwui/Snapshot.h +++ b/libs/hwui/Snapshot.h @@ -22,6 +22,8 @@ #include <utils/RefBase.h> +#include <SkRegion.h> + #include "Layer.h" #include "Matrix.h" #include "Rect.h" @@ -40,7 +42,7 @@ namespace uirenderer { */ class Snapshot: public LightRefBase<Snapshot> { public: - Snapshot(): layer(NULL), fbo(0) { } + Snapshot(): flags(0x0), previous(NULL), layer(NULL), fbo(0) { } /** * Copies the specified snapshot. Only the transform and clip rectangle @@ -52,12 +54,10 @@ public: height(s->height), transform(s->transform), clipRect(s->clipRect), - flags(kFlagDirtyTransform), + flags(0x0), previous(s), layer(NULL), fbo(s->fbo) { - mappedClip.set(s->clipRect); - transform.mapRect(mappedClip); } /** @@ -70,38 +70,48 @@ public: */ kFlagClipSet = 0x1, /** - * Indicates that the snapshot holds new transform - * information. - */ - kFlagDirtyTransform = 0x2, - /** * Indicates that this snapshot was created when saving * a new layer. */ - kFlagIsLayer = 0x4, + kFlagIsLayer = 0x2, /** * Indicates that this snapshot has changed the ortho matrix. */ - kFlagDirtyOrtho = 0x8, + kFlagDirtyOrtho = 0x4, }; /** - * Returns the current clip region mapped by the current transform. - */ - const Rect& getMappedClip() { - return mappedClip; - } - - /** * Intersects the current clip with the new clip rectangle. */ - bool clip(float left, float top, float right, float bottom) { - bool clipped = clipRect.intersect(left, top, right, bottom); - if (flags & kFlagDirtyTransform) { - flags &= ~kFlagDirtyTransform; - mappedClip.set(clipRect); - transform.mapRect(mappedClip); + bool clip(float left, float top, float right, float bottom, SkRegion::Op op) { + bool clipped = false; + + Rect r(left, top, right, bottom); + transform.mapRect(r); + + switch (op) { + case SkRegion::kDifference_Op: + break; + case SkRegion::kIntersect_Op: + clipped = clipRect.intersect(r); + break; + case SkRegion::kUnion_Op: + clipped = clipRect.unionWith(r); + break; + case SkRegion::kXOR_Op: + break; + case SkRegion::kReverseDifference_Op: + break; + case SkRegion::kReplace_Op: + clipRect.set(r); + clipped = true; + break; } + + if (clipped) { + flags |= Snapshot::kFlagClipSet; + } + return clipped; } @@ -110,11 +120,15 @@ public: */ void setClip(float left, float top, float right, float bottom) { clipRect.set(left, top, right, bottom); - if (flags & kFlagDirtyTransform) { - flags &= ~kFlagDirtyTransform; - mappedClip.set(clipRect); - transform.mapRect(mappedClip); - } + flags |= Snapshot::kFlagClipSet; + } + + const Rect& getLocalClip() { + mat4 inverse; + inverse.loadInverse(transform); + localClip.set(clipRect); + inverse.mapRect(localClip); + return localClip; } /** @@ -129,7 +143,8 @@ public: mat4 transform; /** - * Current clip region. + * Current clip region. The clip is stored in canvas-space coordinates, + * (screen-space coordinates in the regular case.) */ Rect clipRect; @@ -155,8 +170,8 @@ public: mat4 orthoMatrix; private: - // Clipping rectangle mapped with the transform - Rect mappedClip; + Rect localClip; + }; // class Snapshot }; // namespace uirenderer |