Add implementations for clipRect(), save() and restore().
The current implementation of clipRect() does not apply local transformations
before setting the new clip.
Change-Id: I5997871bb638dfcd1a8ef96354846af52427e445
diff --git a/libs/hwui/Matrix.cpp b/libs/hwui/Matrix.cpp
index 68b245b..638c1b8 100644
--- a/libs/hwui/Matrix.cpp
+++ b/libs/hwui/Matrix.cpp
@@ -140,10 +140,12 @@
}
void Matrix4::dump() const {
- LOGD("%f %f %f %f", mMat[0], mMat[4], mMat[ 8], mMat[12]);
- LOGD("%f %f %f %f", mMat[1], mMat[5], mMat[ 9], mMat[13]);
- LOGD("%f %f %f %f", mMat[2], mMat[6], mMat[10], mMat[14]);
- LOGD("%f %f %f %f", mMat[3], mMat[7], mMat[11], mMat[15]);
+ LOGD("Matrix4[");
+ LOGD(" %f %f %f %f", mMat[0], mMat[4], mMat[ 8], mMat[12]);
+ LOGD(" %f %f %f %f", mMat[1], mMat[5], mMat[ 9], mMat[13]);
+ LOGD(" %f %f %f %f", mMat[2], mMat[6], mMat[10], mMat[14]);
+ LOGD(" %f %f %f %f", mMat[3], mMat[7], mMat[11], mMat[15]);
+ LOGD("]");
}
};
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index 35825d2..1416ce1 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -35,6 +35,9 @@
OpenGLRenderer::OpenGLRenderer() {
LOGD("Create OpenGLRenderer");
+
+ mSnapshot = new Snapshot;
+ mSaveCount = 0;
}
OpenGLRenderer::~OpenGLRenderer() {
@@ -47,13 +50,80 @@
mat4 ortho;
ortho.loadOrtho(0, width, height, 0, 0, 1);
ortho.copyTo(mOrthoMatrix);
+
+ mWidth = width;
+ mHeight = height;
}
void OpenGLRenderer::prepare() {
glDisable(GL_SCISSOR_TEST);
+
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
glClear(GL_COLOR_BUFFER_BIT);
+
glEnable(GL_SCISSOR_TEST);
+ mSnapshot->clipRect.set(0.0f, 0.0f, mWidth, mHeight);
+}
+
+int OpenGLRenderer::getSaveCount() const {
+ return mSaveCount;
+}
+
+int OpenGLRenderer::save(int flags) {
+ return saveSnapshot();
+}
+
+void OpenGLRenderer::restore() {
+ if (mSaveCount == 0) return;
+
+ if (restoreSnapshot()) {
+ setScissorFromClip();
+ }
+}
+
+void OpenGLRenderer::restoreToCount(int saveCount) {
+ if (saveCount <= 0 || saveCount > mSaveCount) return;
+
+ bool restoreClip = false;
+
+ while (mSaveCount != saveCount - 1) {
+ restoreClip |= restoreSnapshot();
+ }
+
+ if (restoreClip) {
+ setScissorFromClip();
+ }
+}
+
+int OpenGLRenderer::saveSnapshot() {
+ mSnapshot = new Snapshot(mSnapshot);
+ mSaveCount++;
+ return mSaveCount;
+}
+
+bool OpenGLRenderer::restoreSnapshot() {
+ // TODO: handle local transformations
+ bool restoreClip = mSnapshot->flags & Snapshot::kFlagClipSet;
+
+ mSaveCount--;
+ mSnapshot = mSnapshot->previous;
+
+ return restoreClip;
+}
+
+void OpenGLRenderer::setScissorFromClip() {
+ Rect clip = mSnapshot->clipRect;
+ glScissor(clip.left, clip.top, clip.getWidth(), clip.getHeight());
+}
+
+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;
+ setScissorFromClip();
+ }
+ return clipped;
}
void OpenGLRenderer::drawColor(int color, SkXfermode::Mode mode) {
diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h
index 1236336..8a541fc 100644
--- a/libs/hwui/OpenGLRenderer.h
+++ b/libs/hwui/OpenGLRenderer.h
@@ -19,8 +19,32 @@
#include <SkXfermode.h>
+#include <utils/RefBase.h>
+
+#include "Rect.h"
+
namespace android {
+class Snapshot: public LightRefBase<Snapshot> {
+public:
+ Snapshot() { }
+
+ Snapshot(const sp<Snapshot> s): clipRect(s->clipRect), flags(0), previous(s) { }
+
+ enum Flags {
+ kFlagClipSet = 0x1,
+ };
+
+ // Clipping rectangle at the time of this snapshot
+ Rect clipRect;
+
+ // Dirty flags
+ int flags;
+
+ // Previous snapshot in the frames stack
+ sp<Snapshot> previous;
+}; // struct Snapshot
+
class OpenGLRenderer {
public:
OpenGLRenderer();
@@ -29,12 +53,32 @@
void setViewport(int width, int height);
void prepare();
+ int getSaveCount() const;
+ int save(int flags);
+ void restore();
+ void restoreToCount(int saveCount);
+
+ bool clipRect(float left, float top, float right, float bottom);
+
void drawColor(int color, SkXfermode::Mode mode);
private:
+ int saveSnapshot();
+ bool restoreSnapshot();
+
+ void setScissorFromClip();
+
+ // Dimensions of the drawing surface
+ int mWidth, mHeight;
+
// Matrix used for ortho projection in shaders
float mOrthoMatrix[16];
-};
+
+ // Number of saved states
+ int mSaveCount;
+ // Current state
+ sp<Snapshot> mSnapshot;
+}; // class OpenGLRenderer
}; // namespace android
diff --git a/libs/hwui/Rect.h b/libs/hwui/Rect.h
new file mode 100644
index 0000000..724bd1a
--- /dev/null
+++ b/libs/hwui/Rect.h
@@ -0,0 +1,125 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_RECT_H
+#define ANDROID_RECT_H
+
+namespace android {
+
+///////////////////////////////////////////////////////////////////////////////
+// Structs
+///////////////////////////////////////////////////////////////////////////////
+
+struct Rect {
+ float left;
+ float top;
+ float right;
+ float bottom;
+
+ Rect(): left(0), top(0), right(0), bottom(0) { }
+
+ Rect(const Rect& r) {
+ set(r);
+ }
+
+ Rect(Rect& r) {
+ set(r);
+ }
+
+ Rect& operator=(const Rect& r) {
+ set(r);
+ return *this;
+ }
+
+ Rect& operator=(Rect& r) {
+ set(r);
+ return *this;
+ }
+
+ friend int operator==(const Rect& a, const Rect& b) {
+ return !memcmp(&a, &b, sizeof(a));
+ }
+
+ friend int operator!=(const Rect& a, const Rect& b) {
+ return memcmp(&a, &b, sizeof(a));
+ }
+
+ bool isEmpty() const {
+ return left >= right || top >= bottom;
+ }
+
+ void setEmpty() {
+ memset(this, 0, sizeof(*this));
+ }
+
+ void set(float left, float top, float right, float bottom) {
+ this->left = left;
+ this->right = right;
+ this->top = top;
+ this->bottom = bottom;
+ }
+
+ void set(const Rect& r) {
+ set(r.left, r.top, r.right, r.bottom);
+ }
+
+ float getWidth() const {
+ return right - left;
+ }
+
+ float getHeight() const {
+ return bottom - top;
+ }
+
+ bool intersects(float left, float top, float right, float bottom) const {
+ return left < right && top < bottom &&
+ this->left < this->right && this->top < this->bottom &&
+ this->left < right && left < this->right &&
+ this->top < bottom && top < this->bottom;
+ }
+
+ bool intersects(const Rect& r) const {
+ return intersects(r.left, r.top, r.right, r.bottom);
+ }
+
+ bool intersect(float left, float top, float right, float bottom) {
+ if (left < right && top < bottom && !this->isEmpty() &&
+ this->left < right && left < this->right &&
+ this->top < bottom && top < this->bottom) {
+
+ if (this->left < left) this->left = left;
+ if (this->top < top) this->top = top;
+ if (this->right > right) this->right = right;
+ if (this->bottom > bottom) this->bottom = bottom;
+
+ return true;
+ }
+ return false;
+ }
+
+ bool intersect(const Rect& r) {
+ return intersect(r.left, r.top, r.right, r.bottom);
+ }
+
+ void dump() const {
+ LOGD("Rect[l=%f t=%f r=%f b=%f]", left, top, right, bottom);
+ }
+
+}; // struct Rect
+
+}; // namespace android
+
+#endif // ANDROID_RECT_H