Merge "Throw ISE on too-big-views-with-layers"
This commit is contained in:
@@ -49,6 +49,14 @@ using namespace android::uirenderer::renderthread;
|
||||
|
||||
static jmethodID gRunnableMethod;
|
||||
|
||||
static JNIEnv* getenv(JavaVM* vm) {
|
||||
JNIEnv* env;
|
||||
if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
|
||||
LOG_ALWAYS_FATAL("Failed to get JNIEnv for JavaVM: %p", vm);
|
||||
}
|
||||
return env;
|
||||
}
|
||||
|
||||
class JavaTask : public RenderTask {
|
||||
public:
|
||||
JavaTask(JNIEnv* env, jobject jrunnable) {
|
||||
@@ -57,20 +65,13 @@ public:
|
||||
}
|
||||
|
||||
virtual void run() {
|
||||
env()->CallVoidMethod(mRunnable, gRunnableMethod);
|
||||
env()->DeleteGlobalRef(mRunnable);
|
||||
JNIEnv* env = getenv(mVm);
|
||||
env->CallVoidMethod(mRunnable, gRunnableMethod);
|
||||
env->DeleteGlobalRef(mRunnable);
|
||||
delete this;
|
||||
};
|
||||
|
||||
private:
|
||||
JNIEnv* env() {
|
||||
JNIEnv* env;
|
||||
if (mVm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
|
||||
return 0;
|
||||
}
|
||||
return env;
|
||||
}
|
||||
|
||||
JavaVM* mVm;
|
||||
jobject mRunnable;
|
||||
};
|
||||
@@ -122,12 +123,34 @@ private:
|
||||
std::vector<OnFinishedEvent> mOnFinishedEvents;
|
||||
};
|
||||
|
||||
class RootRenderNode : public RenderNode, public AnimationHook {
|
||||
class RenderingException : public MessageHandler {
|
||||
public:
|
||||
RootRenderNode() : RenderNode() {
|
||||
RenderingException(JavaVM* vm, const std::string& message)
|
||||
: mVm(vm)
|
||||
, mMessage(message) {
|
||||
}
|
||||
|
||||
virtual void handleMessage(const Message&) {
|
||||
throwException(mVm, mMessage);
|
||||
}
|
||||
|
||||
static void throwException(JavaVM* vm, const std::string& message) {
|
||||
JNIEnv* env = getenv(vm);
|
||||
jniThrowException(env, "java/lang/IllegalStateException", message.c_str());
|
||||
}
|
||||
|
||||
private:
|
||||
JavaVM* mVm;
|
||||
std::string mMessage;
|
||||
};
|
||||
|
||||
class RootRenderNode : public RenderNode, AnimationHook, ErrorHandler {
|
||||
public:
|
||||
RootRenderNode(JNIEnv* env) : RenderNode() {
|
||||
mLooper = Looper::getForThread();
|
||||
LOG_ALWAYS_FATAL_IF(!mLooper.get(),
|
||||
"Must create RootRenderNode on a thread with a looper!");
|
||||
env->GetJavaVM(&mVm);
|
||||
}
|
||||
|
||||
virtual ~RootRenderNode() {}
|
||||
@@ -137,10 +160,16 @@ public:
|
||||
mOnFinishedEvents.push_back(event);
|
||||
}
|
||||
|
||||
virtual void onError(const std::string& message) {
|
||||
mLooper->sendMessage(new RenderingException(mVm, message), 0);
|
||||
}
|
||||
|
||||
virtual void prepareTree(TreeInfo& info) {
|
||||
info.animationHook = this;
|
||||
info.errorHandler = this;
|
||||
RenderNode::prepareTree(info);
|
||||
info.animationHook = NULL;
|
||||
info.errorHandler = NULL;
|
||||
|
||||
// post all the finished stuff
|
||||
if (mOnFinishedEvents.size()) {
|
||||
@@ -160,6 +189,7 @@ protected:
|
||||
private:
|
||||
sp<Looper> mLooper;
|
||||
std::vector<OnFinishedEvent> mOnFinishedEvents;
|
||||
JavaVM* mVm;
|
||||
};
|
||||
|
||||
static void android_view_ThreadedRenderer_setAtlas(JNIEnv* env, jobject clazz,
|
||||
@@ -178,7 +208,7 @@ static void android_view_ThreadedRenderer_setAtlas(JNIEnv* env, jobject clazz,
|
||||
}
|
||||
|
||||
static jlong android_view_ThreadedRenderer_createRootRenderNode(JNIEnv* env, jobject clazz) {
|
||||
RootRenderNode* node = new RootRenderNode();
|
||||
RootRenderNode* node = new RootRenderNode(env);
|
||||
node->incStrong(0);
|
||||
node->setName("RootRenderNode");
|
||||
return reinterpret_cast<jlong>(node);
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#include "RenderNode.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <string>
|
||||
|
||||
#include <SkCanvas.h>
|
||||
#include <algorithm>
|
||||
@@ -158,7 +159,10 @@ void RenderNode::pushLayerUpdate(TreeInfo& info) {
|
||||
applyLayerPropertiesToLayer(info);
|
||||
damageSelf(info);
|
||||
} else if (mLayer->layer.getWidth() != getWidth() || mLayer->layer.getHeight() != getHeight()) {
|
||||
LayerRenderer::resizeLayer(mLayer, getWidth(), getHeight());
|
||||
if (!LayerRenderer::resizeLayer(mLayer, getWidth(), getHeight())) {
|
||||
LayerRenderer::destroyLayer(mLayer);
|
||||
mLayer = 0;
|
||||
}
|
||||
damageSelf(info);
|
||||
}
|
||||
|
||||
@@ -166,6 +170,15 @@ void RenderNode::pushLayerUpdate(TreeInfo& info) {
|
||||
info.damageAccumulator->peekAtDirty(&dirty);
|
||||
info.damageAccumulator->popTransform();
|
||||
|
||||
if (!mLayer) {
|
||||
if (info.errorHandler) {
|
||||
std::string msg = "Unable to create layer for ";
|
||||
msg += getName();
|
||||
info.errorHandler->onError(msg);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (!dirty.isEmpty()) {
|
||||
mLayer->updateDeferred(this, dirty.fLeft, dirty.fTop, dirty.fRight, dirty.fBottom);
|
||||
}
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
#ifndef TREEINFO_H
|
||||
#define TREEINFO_H
|
||||
|
||||
#include <string>
|
||||
|
||||
#include <utils/Timers.h>
|
||||
|
||||
#include "DamageAccumulator.h"
|
||||
@@ -35,6 +37,13 @@ protected:
|
||||
~AnimationHook() {}
|
||||
};
|
||||
|
||||
class ErrorHandler {
|
||||
public:
|
||||
virtual void onError(const std::string& message) = 0;
|
||||
protected:
|
||||
~ErrorHandler() {}
|
||||
};
|
||||
|
||||
// This would be a struct, but we want to PREVENT_COPY_AND_ASSIGN
|
||||
class TreeInfo {
|
||||
PREVENT_COPY_AND_ASSIGN(TreeInfo);
|
||||
@@ -65,6 +74,7 @@ public:
|
||||
, prepareTextures(mode == MODE_FULL)
|
||||
, damageAccumulator(NullDamageAccumulator::instance())
|
||||
, renderer(0)
|
||||
, errorHandler(0)
|
||||
{}
|
||||
|
||||
const TraversalMode mode;
|
||||
@@ -78,6 +88,7 @@ public:
|
||||
// The renderer that will be drawing the next frame. Use this to push any
|
||||
// layer updates or similar. May be NULL.
|
||||
OpenGLRenderer* renderer;
|
||||
ErrorHandler* errorHandler;
|
||||
|
||||
struct Out {
|
||||
Out()
|
||||
|
||||
Reference in New Issue
Block a user