diff options
author | Romain Guy <romainguy@google.com> | 2010-06-24 19:30:36 -0700 |
---|---|---|
committer | Romain Guy <romainguy@google.com> | 2010-06-24 19:30:36 -0700 |
commit | 9d5316e3f56d138504565ff311145ac01621dff4 (patch) | |
tree | 40c79ba098de4624fbe38cb400c6ac4fe7340673 | |
parent | a18dbdf420fabebb83e7403d000384a8d98daffa (diff) | |
download | frameworks_base-9d5316e3f56d138504565ff311145ac01621dff4.zip frameworks_base-9d5316e3f56d138504565ff311145ac01621dff4.tar.gz frameworks_base-9d5316e3f56d138504565ff311145ac01621dff4.tar.bz2 |
Add colored rectangles implementation in OpenGLRenderer.
Drawing two rectangles one after the other discards the second one because of
Z buffering issues. This will be fixed in another changelist.
Change-Id: Ida1b3cde8a78e60cacc07e477abc44def527ff67
-rw-r--r-- | core/java/android/view/GLES20Canvas.java | 5 | ||||
-rw-r--r-- | core/jni/android_view_GLES20Canvas.cpp | 39 | ||||
-rw-r--r-- | libs/hwui/Matrix.cpp | 21 | ||||
-rw-r--r-- | libs/hwui/Matrix.h | 12 | ||||
-rw-r--r-- | libs/hwui/OpenGLRenderer.cpp | 177 | ||||
-rw-r--r-- | libs/hwui/OpenGLRenderer.h | 79 | ||||
-rw-r--r-- | libs/hwui/Rect.h | 20 | ||||
-rw-r--r-- | libs/hwui/shaders/drawColor.frag | 11 | ||||
-rw-r--r-- | libs/hwui/shaders/drawColor.vert | 16 | ||||
-rw-r--r-- | telephony/java/com/android/internal/telephony/CallManager.java | 2 | ||||
-rw-r--r-- | tests/HwAccelerationTest/src/com/google/android/test/hwui/HwUiActivity.java | 39 |
11 files changed, 395 insertions, 26 deletions
diff --git a/core/java/android/view/GLES20Canvas.java b/core/java/android/view/GLES20Canvas.java index 8df2e86..eb077cb 100644 --- a/core/java/android/view/GLES20Canvas.java +++ b/core/java/android/view/GLES20Canvas.java @@ -186,10 +186,11 @@ class GLES20Canvas extends Canvas { @Override public boolean getClipBounds(Rect bounds) { - // TODO: Implement - return false; + return nGetClipBounds(mRenderer, bounds); } + private native boolean nGetClipBounds(int renderer, Rect bounds); + @Override public boolean quickReject(float left, float top, float right, float bottom, EdgeType type) { // TODO: Implement diff --git a/core/jni/android_view_GLES20Canvas.cpp b/core/jni/android_view_GLES20Canvas.cpp index 1ca172d..95476eb 100644 --- a/core/jni/android_view_GLES20Canvas.cpp +++ b/core/jni/android_view_GLES20Canvas.cpp @@ -22,9 +22,22 @@ #include <SkXfermode.h> #include <OpenGLRenderer.h> +#include <Rect.h> +#include <ui/Rect.h> namespace android { +using namespace uirenderer; + +// ---------------------------------------------------------------------------- +// Java APIs +// ---------------------------------------------------------------------------- + +static struct { + jclass clazz; + jmethodID set; +} gRectClassInfo; + // ---------------------------------------------------------------------------- // Constructors // ---------------------------------------------------------------------------- @@ -90,6 +103,17 @@ static bool android_view_GLES20Renderer_clipRect(JNIEnv* env, jobject canvas, return renderer->clipRect(float(left), float(top), float(right), float(bottom)); } +static bool android_view_GLES20Renderer_getClipBounds(JNIEnv* env, jobject canvas, + OpenGLRenderer* renderer, jobject rect) { + + const android::uirenderer::Rect& bounds(renderer->getClipBounds()); + + env->CallVoidMethod(rect, gRectClassInfo.set, + int(bounds.left), int(bounds.top), int(bounds.right), int(bounds.bottom)); + + return !bounds.isEmpty(); +} + // ---------------------------------------------------------------------------- // Transforms // ---------------------------------------------------------------------------- @@ -153,6 +177,9 @@ static JNINativeMethod gMethods[] = { { "nClipRect", "(IFFFF)Z", (void*) android_view_GLES20Renderer_clipRectF }, { "nClipRect", "(IIIII)Z", (void*) android_view_GLES20Renderer_clipRect }, + { "nGetClipBounds", "(ILandroid/graphics/Rect;)Z", + (void*) android_view_GLES20Renderer_getClipBounds }, + { "nTranslate", "(IFF)V", (void*) android_view_GLES20Renderer_translate }, { "nRotate", "(IF)V", (void*) android_view_GLES20Renderer_rotate }, { "nScale", "(IFF)V", (void*) android_view_GLES20Renderer_scale }, @@ -164,7 +191,19 @@ static JNINativeMethod gMethods[] = { { "nDrawColor", "(III)V", (void*) android_view_GLES20Renderer_drawColor }, }; +#define FIND_CLASS(var, className) \ + var = env->FindClass(className); \ + LOG_FATAL_IF(! var, "Unable to find class " className); \ + var = jclass(env->NewGlobalRef(var)); + +#define GET_METHOD_ID(var, clazz, methodName, methodDescriptor) \ + var = env->GetMethodID(clazz, methodName, methodDescriptor); \ + LOG_FATAL_IF(! var, "Unable to find method " methodName); + int register_android_view_GLES20Canvas(JNIEnv* env) { + FIND_CLASS(gRectClassInfo.clazz, "android/graphics/Rect"); + GET_METHOD_ID(gRectClassInfo.set, gRectClassInfo.clazz, "set", "(IIII)V"); + return AndroidRuntime::registerNativeMethods(env, kClassPathName, gMethods, NELEM(gMethods)); } diff --git a/libs/hwui/Matrix.cpp b/libs/hwui/Matrix.cpp index cbbce38..c097d7f 100644 --- a/libs/hwui/Matrix.cpp +++ b/libs/hwui/Matrix.cpp @@ -14,7 +14,7 @@ * limitations under the License. */ -#define LOG_TAG "UIMatrix" +#define LOG_TAG "Matrix" #include <math.h> #include <stdlib.h> @@ -27,6 +27,7 @@ #include "Matrix.h" namespace android { +namespace uirenderer { void Matrix4::loadIdentity() { mMat[0] = 1.0f; @@ -175,6 +176,21 @@ void Matrix4::loadOrtho(float left, float right, float bottom, float top, float mMat[14] = -(far + near) / (far - near); } +#define MUL_ADD_STORE(a, b, c) a = (a) * (b) + (c) + +void Matrix4::mapRect(Rect& r) const { + const float sx = mMat[0]; + const float sy = mMat[5]; + + const float tx = mMat[12]; + const float ty = mMat[13]; + + MUL_ADD_STORE(r.left, sx, tx); + MUL_ADD_STORE(r.right, sx, tx); + MUL_ADD_STORE(r.top, sy, ty); + MUL_ADD_STORE(r.bottom, sy, ty); +} + void Matrix4::dump() const { LOGD("Matrix4["); LOGD(" %f %f %f %f", mMat[0], mMat[4], mMat[ 8], mMat[12]); @@ -184,4 +200,5 @@ void Matrix4::dump() const { LOGD("]"); } -}; +}; // namespace uirenderer +}; // namespace android diff --git a/libs/hwui/Matrix.h b/libs/hwui/Matrix.h index 80f3fd6..9bd289f 100644 --- a/libs/hwui/Matrix.h +++ b/libs/hwui/Matrix.h @@ -14,12 +14,15 @@ * limitations under the License. */ -#ifndef ANDROID_MATRIX_H -#define ANDROID_MATRIX_H +#ifndef ANDROID_UI_MATRIX_H +#define ANDROID_UI_MATRIX_H #include <SkMatrix.h> +#include "Rect.h" + namespace android { +namespace uirenderer { /////////////////////////////////////////////////////////////////////////////// // Classes @@ -83,6 +86,8 @@ public: void copyTo(float* v) const; void copyTo(SkMatrix& v) const; + void mapRect(Rect& r) const; + void dump() const; private: @@ -103,6 +108,7 @@ private: typedef Matrix4 mat4; +}; // namespace uirenderer }; // namespace android -#endif // ANDROID_MATRIX_H +#endif // ANDROID_UI_MATRIX_H diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp index e19795e..575bc20 100644 --- a/libs/hwui/OpenGLRenderer.cpp +++ b/libs/hwui/OpenGLRenderer.cpp @@ -21,6 +21,7 @@ #include <sys/types.h> #include <utils/Errors.h> +#include <utils/KeyedVector.h> #include <utils/Log.h> #include <GLES2/gl2.h> @@ -32,6 +33,129 @@ #include "Matrix.h" namespace android { +namespace uirenderer { + +/////////////////////////////////////////////////////////////////////////////// +// Defines +/////////////////////////////////////////////////////////////////////////////// + +#define SOLID_WHITE { 1.0f, 1.0f, 1.0f, 1.0f } + +#define P(x, y) { x, y } + +/////////////////////////////////////////////////////////////////////////////// +// Globals +/////////////////////////////////////////////////////////////////////////////// + +const Vertex gDrawColorVertices[] = { + { P(0.0f, 0.0f), SOLID_WHITE }, + { P(1.0f, 0.0f), SOLID_WHITE }, + { P(0.0f, 1.0f), SOLID_WHITE }, + { P(1.0f, 1.0f), SOLID_WHITE } +}; + +/////////////////////////////////////////////////////////////////////////////// +// Shaders +/////////////////////////////////////////////////////////////////////////////// + +#define SHADER_SOURCE(name, source) const char* name = #source + +#include "shaders/drawColor.vert" +#include "shaders/drawColor.frag" + +Program::Program(const char* vertex, const char* fragment) { + vertexShader = buildShader(vertex, GL_VERTEX_SHADER); + fragmentShader = buildShader(fragment, GL_FRAGMENT_SHADER); + + id = glCreateProgram(); + glAttachShader(id, vertexShader); + glAttachShader(id, fragmentShader); + glLinkProgram(id); + + GLint status; + glGetProgramiv(id, GL_LINK_STATUS, &status); + if (status != GL_TRUE) { + GLint infoLen = 0; + glGetProgramiv(id, GL_INFO_LOG_LENGTH, &infoLen); + if (infoLen > 1) { + char* log = (char*) malloc(sizeof(char) * infoLen); + glGetProgramInfoLog(id, infoLen, 0, log); + LOGE("Error while linking shaders: %s", log); + delete log; + } + glDeleteProgram(id); + } +} + +Program::~Program() { + glDeleteShader(vertexShader); + glDeleteShader(fragmentShader); + glDeleteProgram(id); +} + +void Program::use() { + glUseProgram(id); +} + +int Program::addAttrib(const char* name) { + int slot = glGetAttribLocation(id, name); + attributes.add(name, slot); + return slot; +} + +int Program::getAttrib(const char* name) { + return attributes.valueFor(name); +} + +int Program::addUniform(const char* name) { + int slot = glGetUniformLocation(id, name); + uniforms.add(name, slot); + return slot; +} + +int Program::getUniform(const char* name) { + return uniforms.valueFor(name); +} + +GLuint Program::buildShader(const char* source, GLenum type) { + GLuint shader = glCreateShader(type); + glShaderSource(shader, 1, &source, 0); + glCompileShader(shader); + + GLint status; + glGetShaderiv(shader, GL_COMPILE_STATUS, &status); + if (status != GL_TRUE) { + // Some drivers return wrong values for GL_INFO_LOG_LENGTH + // use a fixed size instead + GLchar log[512]; + glGetShaderInfoLog(shader, sizeof(log), 0, &log[0]); + LOGE("Error while compiling shader: %s", log); + glDeleteShader(shader); + } + + return shader; +} + +DrawColorProgram::DrawColorProgram(): + Program(gDrawColorVertexShader, gDrawColorFragmentShader) { + position = addAttrib("position"); + color = addAttrib("color"); + projection = addUniform("projection"); + modelView = addUniform("modelView"); +} + +/////////////////////////////////////////////////////////////////////////////// +// Support +/////////////////////////////////////////////////////////////////////////////// + +const Rect& Snapshot::getMappedClip() { + if (flags & kFlagDirtyTransform) { + flags &= ~kFlagDirtyTransform; + mappedClip.set(clipRect); + transform.mapRect(mappedClip); + } + return mappedClip; +} /////////////////////////////////////////////////////////////////////////////// // Constructors/destructor @@ -39,6 +163,8 @@ namespace android { OpenGLRenderer::OpenGLRenderer() { LOGD("Create OpenGLRenderer"); + + mDrawColorShader = new DrawColorProgram; } OpenGLRenderer::~OpenGLRenderer() { @@ -114,7 +240,6 @@ int OpenGLRenderer::saveSnapshot() { } bool OpenGLRenderer::restoreSnapshot() { - // TODO: handle local transformations bool restoreClip = mSnapshot->flags & Snapshot::kFlagClipSet; mSaveCount--; @@ -132,18 +257,22 @@ bool OpenGLRenderer::restoreSnapshot() { 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) { @@ -153,6 +282,7 @@ void OpenGLRenderer::getMatrix(SkMatrix* matrix) { void OpenGLRenderer::concatMatrix(SkMatrix* matrix) { mat4 m(*matrix); mSnapshot->transform.multiply(m); + mSnapshot->flags |= Snapshot::kFlagDirtyTransform; } /////////////////////////////////////////////////////////////////////////////// @@ -160,12 +290,15 @@ void OpenGLRenderer::concatMatrix(SkMatrix* matrix) { /////////////////////////////////////////////////////////////////////////////// void OpenGLRenderer::setScissorFromClip() { - Rect* clip = &(mSnapshot->clipRect); - glScissor(clip->left, clip->top, clip->getWidth(), clip->getHeight()); + const Rect& clip = mSnapshot->getMappedClip(); + glScissor(clip.left, clip.top, clip.getWidth(), clip.getHeight()); +} + +const Rect& OpenGLRenderer::getClipBounds() { + return mSnapshot->clipRect; } bool OpenGLRenderer::clipRect(float left, float top, float right, float bottom) { - // TODO: take local translate transform into account bool clipped = mSnapshot->clipRect.intersect(left, top, right, bottom); if (clipped) { mSnapshot->flags |= Snapshot::kFlagClipSet; @@ -179,7 +312,41 @@ bool OpenGLRenderer::clipRect(float left, float top, float right, float bottom) /////////////////////////////////////////////////////////////////////////////// void OpenGLRenderer::drawColor(int color, SkXfermode::Mode mode) { - LOGD("Drawing color"); + GLfloat a = ((color >> 24) & 0xFF) / 255.0f; + GLfloat r = ((color >> 16) & 0xFF) / 255.0f; + GLfloat g = ((color >> 8) & 0xFF) / 255.0f; + GLfloat b = ((color ) & 0xFF) / 255.0f; + + // TODO Optimize this section + const Rect& clip = mSnapshot->getMappedClip(); + + mat4 modelView; + modelView.loadScale(clip.getWidth(), clip.getHeight(), 1.0f); + modelView.translate(clip.left, clip.top, 0.0f); + + float matrix[16]; + modelView.copyTo(matrix); + // TODO Optimize this section + + mDrawColorShader->use(); + + glUniformMatrix4fv(mDrawColorShader->projection, 1, GL_FALSE, &mOrthoMatrix[0]); + glUniformMatrix4fv(mDrawColorShader->modelView, 1, GL_FALSE, &matrix[0]); + + glEnableVertexAttribArray(mDrawColorShader->position); + + GLsizei stride = sizeof(Vertex); + const GLvoid* p = &gDrawColorVertices[0].position[0]; + + glVertexAttribPointer(mDrawColorShader->position, 2, GL_FLOAT, GL_FALSE, stride, p); + glVertexAttrib4f(mDrawColorShader->color, r, g, b, a); + + GLsizei vertexCount = sizeof(gDrawColorVertices) / sizeof(Vertex); + glDrawArrays(GL_TRIANGLE_STRIP, 0, vertexCount); + + glDisableVertexAttribArray(mDrawColorShader->position); + glDisableVertexAttribArray(mDrawColorShader->color); } +}; // namespace uirenderer }; // namespace android diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h index 595768c..88cbc1c 100644 --- a/libs/hwui/OpenGLRenderer.h +++ b/libs/hwui/OpenGLRenderer.h @@ -14,18 +14,23 @@ * limitations under the License. */ -#ifndef ANDROID_OPENGL_RENDERER_H -#define ANDROID_OPENGL_RENDERER_H +#ifndef ANDROID_UI_OPENGL_RENDERER_H +#define ANDROID_UI_OPENGL_RENDERER_H + +#include <GLES2/gl2.h> +#include <GLES2/gl2ext.h> #include <SkMatrix.h> #include <SkXfermode.h> +#include <utils/KeyedVector.h> #include <utils/RefBase.h> #include "Matrix.h" #include "Rect.h" namespace android { +namespace uirenderer { /////////////////////////////////////////////////////////////////////////////// // Support @@ -36,14 +41,20 @@ public: Snapshot() { } - Snapshot(const sp<Snapshot> s): transform(s->transform), clipRect(s->clipRect), - flags(0), previous(s) { + Snapshot(const sp<Snapshot> s): + transform(s->transform), + clipRect(s->clipRect), + flags(kFlagDirtyTransform), + previous(s) { } enum Flags { kFlagClipSet = 0x1, + kFlagDirtyTransform = 0x2, }; + const Rect& getMappedClip(); + // Local transformations mat4 transform; @@ -55,7 +66,58 @@ public: // Previous snapshot in the frames stack sp<Snapshot> previous; -}; // struct Snapshot + +private: + // Clipping rectangle mapped with the transform + Rect mappedClip; +}; // class Snapshot + +struct Vertex { + float position[2]; + float color[4]; +}; // struct Vertex + +typedef char* shader; + +class Program: public LightRefBase<Program> { +public: + Program(const char* vertex, const char* fragment); + ~Program(); + + void use(); + +protected: + int addAttrib(const char* name); + int getAttrib(const char* name); + + int addUniform(const char* name); + int getUniform(const char* name); + +private: + GLuint buildShader(const char* source, GLenum type); + + // Handle of the OpenGL program + GLuint id; + + // Handles of the shaders + GLuint vertexShader; + GLuint fragmentShader; + + // Keeps track of attributes and uniforms slots + KeyedVector<const char*, int> attributes; + KeyedVector<const char*, int> uniforms; +}; // class Program + +class DrawColorProgram: public Program { +public: + DrawColorProgram(); + + int position; + int color; + + int projection; + int modelView; +}; /////////////////////////////////////////////////////////////////////////////// // Renderer @@ -82,6 +144,7 @@ public: void getMatrix(SkMatrix* matrix); void concatMatrix(SkMatrix* matrix); + const Rect& getClipBounds(); bool clipRect(float left, float top, float right, float bottom); void drawColor(int color, SkXfermode::Mode mode); @@ -104,8 +167,12 @@ private: Snapshot mFirstSnapshot; // Current state sp<Snapshot> mSnapshot; + + // Shaders + sp<DrawColorProgram> mDrawColorShader; }; // class OpenGLRenderer +}; // namespace uirenderer }; // namespace android -#endif // ANDROID_OPENGL_RENDERER_H +#endif // ANDROID_UI_OPENGL_RENDERER_H diff --git a/libs/hwui/Rect.h b/libs/hwui/Rect.h index 724bd1a..fcf11e9 100644 --- a/libs/hwui/Rect.h +++ b/libs/hwui/Rect.h @@ -14,10 +14,11 @@ * limitations under the License. */ -#ifndef ANDROID_RECT_H -#define ANDROID_RECT_H +#ifndef ANDROID_UI_RECT_H +#define ANDROID_UI_RECT_H namespace android { +namespace uirenderer { /////////////////////////////////////////////////////////////////////////////// // Structs @@ -29,7 +30,19 @@ struct Rect { float right; float bottom; - Rect(): left(0), top(0), right(0), bottom(0) { } + Rect(): + left(0), + top(0), + right(0), + bottom(0) { + } + + Rect(float left, float top, float right, float bottom): + left(left), + top(top), + right(right), + bottom(bottom) { + } Rect(const Rect& r) { set(r); @@ -120,6 +133,7 @@ struct Rect { }; // struct Rect +}; // namespace uirenderer }; // namespace android #endif // ANDROID_RECT_H diff --git a/libs/hwui/shaders/drawColor.frag b/libs/hwui/shaders/drawColor.frag new file mode 100644 index 0000000..f753abb --- /dev/null +++ b/libs/hwui/shaders/drawColor.frag @@ -0,0 +1,11 @@ +SHADER_SOURCE(gDrawColorFragmentShader, + +precision mediump float; + +varying vec4 outColor; + +void main(void) { + gl_FragColor = outColor; +} + +); diff --git a/libs/hwui/shaders/drawColor.vert b/libs/hwui/shaders/drawColor.vert new file mode 100644 index 0000000..fd3cb45 --- /dev/null +++ b/libs/hwui/shaders/drawColor.vert @@ -0,0 +1,16 @@ +SHADER_SOURCE(gDrawColorVertexShader, + +attribute vec4 position; +attribute vec4 color; + +uniform mat4 projection; +uniform mat4 modelView; + +varying vec4 outColor; + +void main(void) { + outColor = color; + gl_Position = projection * modelView * position; +} + +); diff --git a/telephony/java/com/android/internal/telephony/CallManager.java b/telephony/java/com/android/internal/telephony/CallManager.java index c548349..1ebf68a 100644 --- a/telephony/java/com/android/internal/telephony/CallManager.java +++ b/telephony/java/com/android/internal/telephony/CallManager.java @@ -207,7 +207,7 @@ public final class CallManager { * java.lang.Object) registerForPreciseCallStateChanged()}. * * @exception CallStateException if active call is ringing, waiting, or - * dialing/alerting, or heldCall can�t be active. + * dialing/alerting, or heldCall can't be active. * In these cases, this operation may not be performed. */ public void switchHoldingAndActive(Call heldCall) throws CallStateException { diff --git a/tests/HwAccelerationTest/src/com/google/android/test/hwui/HwUiActivity.java b/tests/HwAccelerationTest/src/com/google/android/test/hwui/HwUiActivity.java index d24f027..81b9357 100644 --- a/tests/HwAccelerationTest/src/com/google/android/test/hwui/HwUiActivity.java +++ b/tests/HwAccelerationTest/src/com/google/android/test/hwui/HwUiActivity.java @@ -18,14 +18,13 @@ package com.google.android.test.hwui; import android.app.Activity; import android.content.Context; -import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Paint; import android.os.Bundle; +import android.util.Log; import android.view.View; -import static android.util.Log.d; - +@SuppressWarnings({"UnusedDeclaration"}) public class HwUiActivity extends Activity { private static final String LOG_TAG = "HwUi"; @@ -42,15 +41,47 @@ public class HwUiActivity extends Activity { } static class DirtyBitmapView extends View { + private final Paint mPaint; + DirtyBitmapView(Context c) { super(c); + mPaint = new Paint(); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); - canvas.drawRGB(255, 0, 0); + canvas.drawRGB(255, 255, 255); + + mPaint.setColor(0xffff0000); + canvas.drawRect(200.0f, 0.0f, 220.0f, 20.0f, mPaint); + + canvas.save(); + canvas.clipRect(20.0f, 0.0f, 40.0f, 20.0f); + Log.d(LOG_TAG, "clipRect = " + canvas.getClipBounds()); + canvas.restore(); + + canvas.save(); + canvas.scale(2.0f, 2.0f); + canvas.clipRect(20.0f, 0.0f, 40.0f, 20.0f); + Log.d(LOG_TAG, "clipRect = " + canvas.getClipBounds()); + canvas.restore(); + + canvas.save(); + canvas.translate(20.0f, 20.0f); + canvas.clipRect(20.0f, 0.0f, 40.0f, 20.0f); + Log.d(LOG_TAG, "clipRect = " + canvas.getClipBounds()); + canvas.restore(); + + canvas.scale(2.0f, 2.0f); + canvas.clipRect(20.0f, 0.0f, 40.0f, 20.0f); + + mPaint.setColor(0xff00ff00); + canvas.drawRect(0.0f, 0.0f, 20.0f, 20.0f, mPaint); + + mPaint.setColor(0xff0000ff); + canvas.drawRect(20.0f, 0.0f, 40.0f, 20.0f, mPaint); } } } |