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
This commit is contained in:
@@ -137,9 +137,10 @@ class GLES20Canvas extends Canvas {
|
||||
|
||||
@Override
|
||||
public boolean clipRect(float left, float top, float right, float bottom) {
|
||||
// TODO: Implement
|
||||
return false;
|
||||
return nClipRect(mRenderer, left, top, right, bottom);
|
||||
}
|
||||
|
||||
private native boolean nClipRect(int renderer, float left, float top, float right, float bottom);
|
||||
|
||||
@Override
|
||||
public boolean clipRect(float left, float top, float right, float bottom, Region.Op op) {
|
||||
@@ -148,14 +149,14 @@ class GLES20Canvas extends Canvas {
|
||||
|
||||
@Override
|
||||
public boolean clipRect(int left, int top, int right, int bottom) {
|
||||
// TODO: Implement
|
||||
return false;
|
||||
return nClipRect(mRenderer, left, top, right, bottom);
|
||||
}
|
||||
|
||||
private native boolean nClipRect(int renderer, int left, int top, int right, int bottom);
|
||||
|
||||
@Override
|
||||
public boolean clipRect(Rect rect) {
|
||||
// TODO: Implement
|
||||
return false;
|
||||
return clipRect(rect.left, rect.top, rect.right, rect.bottom);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -165,8 +166,7 @@ class GLES20Canvas extends Canvas {
|
||||
|
||||
@Override
|
||||
public boolean clipRect(RectF rect) {
|
||||
// TODO: Implement
|
||||
return false;
|
||||
return clipRect(rect.left, rect.top, rect.right, rect.bottom);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -198,14 +198,12 @@ class GLES20Canvas extends Canvas {
|
||||
|
||||
@Override
|
||||
public boolean quickReject(Path path, EdgeType type) {
|
||||
// TODO: Implement
|
||||
return false;
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean quickReject(RectF rect, EdgeType type) {
|
||||
// TODO: Implement
|
||||
return false;
|
||||
return quickReject(rect.left, rect.top, rect.right, rect.bottom, type);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
@@ -254,16 +252,16 @@ class GLES20Canvas extends Canvas {
|
||||
|
||||
@Override
|
||||
public int save() {
|
||||
// TODO: Implement
|
||||
return 0;
|
||||
return nSave(mRenderer, 0);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public int save(int saveFlags) {
|
||||
// TODO: Implement
|
||||
return 0;
|
||||
return nSave(mRenderer, saveFlags);
|
||||
}
|
||||
|
||||
private native int nSave(int renderer, int flags);
|
||||
|
||||
@Override
|
||||
public int saveLayer(RectF bounds, Paint paint, int saveFlags) {
|
||||
// TODO: Implement
|
||||
@@ -292,19 +290,24 @@ class GLES20Canvas extends Canvas {
|
||||
|
||||
@Override
|
||||
public void restore() {
|
||||
// TODO: Implement
|
||||
nRestore(mRenderer);
|
||||
}
|
||||
|
||||
private native void nRestore(int renderer);
|
||||
|
||||
@Override
|
||||
public void restoreToCount(int saveCount) {
|
||||
// TODO: Implement
|
||||
nRestoreToCount(mRenderer, saveCount);
|
||||
}
|
||||
|
||||
private native void nRestoreToCount(int renderer, int saveCount);
|
||||
|
||||
@Override
|
||||
public int getSaveCount() {
|
||||
// TODO: Implement
|
||||
return 0;
|
||||
return nGetSaveCount(mRenderer);
|
||||
}
|
||||
|
||||
private native int nGetSaveCount(int renderer);
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Filtering
|
||||
|
||||
@@ -54,7 +54,47 @@ static void android_view_GLES20Renderer_prepare(JNIEnv* env, jobject canvas, jin
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Draw color
|
||||
// State
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
static jint android_view_GLES20Renderer_save(JNIEnv* env, jobject canvas, jint renderer,
|
||||
jint flags) {
|
||||
|
||||
return UI->save(flags);
|
||||
}
|
||||
|
||||
static jint android_view_GLES20Renderer_getSaveCount(JNIEnv* env, jobject canvas, jint renderer) {
|
||||
return UI->getSaveCount();
|
||||
}
|
||||
|
||||
static void android_view_GLES20Renderer_restore(JNIEnv* env, jobject canvas, jint renderer) {
|
||||
UI->restore();
|
||||
}
|
||||
|
||||
static void android_view_GLES20Renderer_restoreToCount(JNIEnv* env, jobject canvas, jint renderer,
|
||||
jint saveCount) {
|
||||
|
||||
UI->restoreToCount(saveCount);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Clipping
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
static bool android_view_GLES20Renderer_clipRectF(JNIEnv* env, jobject canvas, jint renderer,
|
||||
jfloat left, jfloat top, jfloat right, jfloat bottom) {
|
||||
|
||||
return UI->clipRect(left, top, right, bottom);
|
||||
}
|
||||
|
||||
static bool android_view_GLES20Renderer_clipRect(JNIEnv* env, jobject canvas, jint renderer,
|
||||
jint left, jint top, jint right, jint bottom) {
|
||||
|
||||
return UI->clipRect(float(left), float(top), float(right), float(bottom));
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Drawing
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
static void android_view_GLES20Renderer_drawColor(JNIEnv* env, jobject canvas, jint renderer,
|
||||
@@ -70,12 +110,20 @@ static void android_view_GLES20Renderer_drawColor(JNIEnv* env, jobject canvas, j
|
||||
const char* const kClassPathName = "android/view/GLES20Canvas";
|
||||
|
||||
static JNINativeMethod gMethods[] = {
|
||||
{ "nCreateRenderer", "()I", (void*) android_view_GLES20Renderer_createRenderer },
|
||||
{ "nDestroyRenderer", "(I)V", (void*) android_view_GLES20Renderer_destroyRenderer },
|
||||
{ "nSetViewport", "(III)V", (void*) android_view_GLES20Renderer_setViewport },
|
||||
{ "nPrepare", "(I)V", (void*) android_view_GLES20Renderer_prepare },
|
||||
{ "nCreateRenderer", "()I", (void*) android_view_GLES20Renderer_createRenderer },
|
||||
{ "nDestroyRenderer", "(I)V", (void*) android_view_GLES20Renderer_destroyRenderer },
|
||||
{ "nSetViewport", "(III)V", (void*) android_view_GLES20Renderer_setViewport },
|
||||
{ "nPrepare", "(I)V", (void*) android_view_GLES20Renderer_prepare },
|
||||
|
||||
{ "nDrawColor", "(III)V", (void*) android_view_GLES20Renderer_drawColor },
|
||||
{ "nSave", "(II)I", (void*) android_view_GLES20Renderer_save },
|
||||
{ "nRestore", "(I)V", (void*) android_view_GLES20Renderer_restore },
|
||||
{ "nRestoreToCount", "(II)V", (void*) android_view_GLES20Renderer_restoreToCount },
|
||||
{ "nGetSaveCount", "(I)I", (void*) android_view_GLES20Renderer_getSaveCount },
|
||||
|
||||
{ "nClipRect", "(IFFFF)Z", (void*) android_view_GLES20Renderer_clipRectF },
|
||||
{ "nClipRect", "(IIIII)Z", (void*) android_view_GLES20Renderer_clipRect },
|
||||
|
||||
{ "nDrawColor", "(III)V", (void*) android_view_GLES20Renderer_drawColor },
|
||||
};
|
||||
|
||||
int register_android_view_GLES20Canvas(JNIEnv* env) {
|
||||
|
||||
@@ -140,10 +140,12 @@ void Matrix4::loadOrtho(float left, float right, float bottom, float top, float
|
||||
}
|
||||
|
||||
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("]");
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
@@ -35,6 +35,9 @@ namespace android {
|
||||
|
||||
OpenGLRenderer::OpenGLRenderer() {
|
||||
LOGD("Create OpenGLRenderer");
|
||||
|
||||
mSnapshot = new Snapshot;
|
||||
mSaveCount = 0;
|
||||
}
|
||||
|
||||
OpenGLRenderer::~OpenGLRenderer() {
|
||||
@@ -47,13 +50,80 @@ void OpenGLRenderer::setViewport(int width, int height) {
|
||||
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) {
|
||||
|
||||
@@ -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 @@ public:
|
||||
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
|
||||
|
||||
|
||||
125
libs/hwui/Rect.h
Normal file
125
libs/hwui/Rect.h
Normal file
@@ -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
|
||||
Reference in New Issue
Block a user