summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRomain Guy <romainguy@google.com>2010-07-08 19:17:03 -0700
committerRomain Guy <romainguy@google.com>2010-07-08 19:19:07 -0700
commitf7f93556c8fcc640ab5adef79d021a80a72a645a (patch)
tree71fc93983fc54c32a0051890b719e6f20ec90003
parent26be805f4242af9d511584663e88dfae235d74a4 (diff)
downloadframeworks_base-f7f93556c8fcc640ab5adef79d021a80a72a645a.zip
frameworks_base-f7f93556c8fcc640ab5adef79d021a80a72a645a.tar.gz
frameworks_base-f7f93556c8fcc640ab5adef79d021a80a72a645a.tar.bz2
Draw n-patches using OpenGL.
Currently only tested with title bars and buttons. Change-Id: I8263a9281898dc0e943b1b8412827fe55639b9d6
-rw-r--r--libs/hwui/Android.mk1
-rw-r--r--libs/hwui/Layer.h4
-rw-r--r--libs/hwui/LayerCache.h2
-rw-r--r--libs/hwui/OpenGLRenderer.cpp131
-rw-r--r--libs/hwui/OpenGLRenderer.h35
-rw-r--r--libs/hwui/Patch.h129
-rw-r--r--libs/hwui/PatchCache.cpp72
-rw-r--r--libs/hwui/PatchCache.h65
-rw-r--r--libs/hwui/Vertex.h49
-rw-r--r--tests/HwAccelerationTest/AndroidManifest.xml9
-rw-r--r--tests/HwAccelerationTest/src/com/google/android/test/hwui/NinePatchesActivity.java40
11 files changed, 506 insertions, 31 deletions
diff --git a/libs/hwui/Android.mk b/libs/hwui/Android.mk
index 9146ba6..2d6263d 100644
--- a/libs/hwui/Android.mk
+++ b/libs/hwui/Android.mk
@@ -5,6 +5,7 @@ LOCAL_SRC_FILES:= \
LayerCache.cpp \
Matrix.cpp \
OpenGLRenderer.cpp \
+ PatchCache.cpp \
Program.cpp \
TextureCache.cpp
diff --git a/libs/hwui/Layer.h b/libs/hwui/Layer.h
index 586a05e..d4db782 100644
--- a/libs/hwui/Layer.h
+++ b/libs/hwui/Layer.h
@@ -17,6 +17,8 @@
#ifndef ANDROID_UI_LAYER_H
#define ANDROID_UI_LAYER_H
+#include <sys/types.h>
+
#include <GLES2/gl2.h>
#include <SkXfermode.h>
@@ -54,7 +56,7 @@ struct LayerSize {
bool operator==(const LayerSize& rhs) const {
return width == rhs.width && height == rhs.height;
}
-};
+}; // struct LayerSize
/**
* A layer has dimensions and is backed by an OpenGL texture.
diff --git a/libs/hwui/LayerCache.h b/libs/hwui/LayerCache.h
index adc6713..2580551 100644
--- a/libs/hwui/LayerCache.h
+++ b/libs/hwui/LayerCache.h
@@ -50,7 +50,7 @@ public:
* Used as a callback when an entry is removed from the cache.
* Do not invoke directly.
*/
- void operator()(LayerSize& bitmap, Layer*& texture);
+ void operator()(LayerSize& size, Layer*& layer);
/**
* Returns the layer of specified dimensions. If not suitable layer
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index 027ed79..34da572 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -40,6 +40,7 @@ namespace uirenderer {
#define DEFAULT_TEXTURE_CACHE_SIZE 20
#define DEFAULT_LAYER_CACHE_SIZE 10
+#define DEFAULT_PATCH_CACHE_SIZE 100
// Converts a number of mega-bytes into bytes
#define MB(s) s * 1024 * 1024
@@ -95,7 +96,8 @@ static const Blender gBlends[] = {
OpenGLRenderer::OpenGLRenderer():
mTextureCache(MB(DEFAULT_TEXTURE_CACHE_SIZE)),
- mLayerCache(MB(DEFAULT_LAYER_CACHE_SIZE)) {
+ mLayerCache(MB(DEFAULT_LAYER_CACHE_SIZE)),
+ mPatchCache(DEFAULT_PATCH_CACHE_SIZE) {
LOGD("Create OpenGLRenderer");
char property[PROPERTY_VALUE_MAX];
@@ -298,7 +300,6 @@ bool OpenGLRenderer::createLayer(sp<Snapshot> snapshot, float left, float top,
GLuint previousFbo = snapshot->previous.get() ? snapshot->previous->fbo : 0;
LayerSize size(right - left, bottom - top);
- // TODO VERY IMPORTANT: Fix TextView to not call saveLayer() all the time
Layer* layer = mLayerCache.get(size, previousFbo);
if (!layer) {
return false;
@@ -472,8 +473,110 @@ void OpenGLRenderer::drawBitmap(SkBitmap* bitmap,
void OpenGLRenderer::drawPatch(SkBitmap* bitmap, Res_png_9patch* patch,
float left, float top, float right, float bottom, const SkPaint* paint) {
- // TODO: Implement
- LOGD("Draw 9patch, paddingLeft=%d", patch->paddingLeft);
+ const Texture* texture = mTextureCache.get(bitmap);
+
+ int alpha;
+ SkXfermode::Mode mode;
+ getAlphaAndMode(paint, &alpha, &mode);
+
+ const uint32_t width = patch->numXDivs;
+ const uint32_t height = patch->numYDivs;
+
+ Patch* mesh = mPatchCache.get(patch);
+
+ const uint32_t xStretchCount = (width + 1) >> 1;
+ const uint32_t yStretchCount = (height + 1) >> 1;
+
+ const int32_t* xDivs = &patch->xDivs[0];
+ const int32_t* yDivs = &patch->yDivs[0];
+
+ float xStretch = 0;
+ float yStretch = 0;
+ float xStretchTex = 0;
+ float yStretchTex = 0;
+
+ const float meshWidth = right - left;
+
+ const float bitmapWidth = float(bitmap->width());
+ const float bitmapHeight = float(bitmap->height());
+
+ if (xStretchCount > 0) {
+ uint32_t stretchSize = 0;
+ for (uint32_t i = 1; i < width; i += 2) {
+ stretchSize += xDivs[i] - xDivs[i - 1];
+ }
+ xStretchTex = (stretchSize / bitmapWidth) / xStretchCount;
+ const float fixed = bitmapWidth - stretchSize;
+ xStretch = (right - left - fixed) / xStretchCount;
+ }
+
+ if (yStretchCount > 0) {
+ uint32_t stretchSize = 0;
+ for (uint32_t i = 1; i < height; i += 2) {
+ stretchSize += yDivs[i] - yDivs[i - 1];
+ }
+ yStretchTex = (stretchSize / bitmapHeight) / yStretchCount;
+ const float fixed = bitmapHeight - stretchSize;
+ yStretch = (bottom - top - fixed) / yStretchCount;
+ }
+
+ float vy = 0.0f;
+ float ty = 0.0f;
+ TextureVertex* vertex = mesh->vertices;
+
+ generateVertices(vertex, 0.0f, 0.0f, xDivs, width, xStretch, xStretchTex,
+ meshWidth, bitmapWidth);
+ vertex += width + 2;
+
+ for (uint32_t y = 0; y < height; y++) {
+ if (y & 1) {
+ vy += yStretch;
+ ty += yStretchTex;
+ } else {
+ const float step = float(yDivs[y]);
+ vy += step;
+ ty += step / bitmapHeight;
+ }
+ generateVertices(vertex, vy, ty, xDivs, width, xStretch, xStretchTex,
+ meshWidth, bitmapWidth);
+ vertex += width + 2;
+ }
+
+ generateVertices(vertex, bottom - top, 1.0f, xDivs, width, xStretch, xStretchTex,
+ meshWidth, bitmapWidth);
+
+ // Specify right and bottom as +1.0f from left/top to prevent scaling since the
+ // patch mesh already defines the final size
+ drawTextureMesh(left, top, left + 1.0f, top + 1.0f, texture->id, alpha, mode, texture->blend,
+ true, &mesh->vertices[0].position[0], &mesh->vertices[0].texture[0], mesh->indices,
+ mesh->indicesCount);
+}
+
+void OpenGLRenderer::generateVertices(TextureVertex* vertex, float y, float v,
+ const int32_t xDivs[], uint32_t xCount, float xStretch, float xStretchTex,
+ float width, float widthTex) {
+ float vx = 0.0f;
+ float tx = 0.0f;
+
+ TextureVertex::set(vertex, vx, y, tx, v);
+ vertex++;
+
+ for (uint32_t x = 0; x < xCount; x++) {
+ if (x & 1) {
+ vx += xStretch;
+ tx += xStretchTex;
+ } else {
+ const float step = float(xDivs[x]);
+ vx += step;
+ tx += step / widthTex;
+ }
+
+ TextureVertex::set(vertex, vx, y, tx, v);
+ vertex++;
+ }
+
+ TextureVertex::set(vertex, width, y, 1.0f, v);
+ vertex++;
}
void OpenGLRenderer::drawColor(int color, SkXfermode::Mode mode) {
@@ -538,6 +641,13 @@ void OpenGLRenderer::drawColorRect(float left, float top, float right, float bot
void OpenGLRenderer::drawTextureRect(float left, float top, float right, float bottom,
GLuint texture, float alpha, SkXfermode::Mode mode, bool blend, bool isPremultiplied) {
+ drawTextureMesh(left, top, right, bottom, texture, alpha, mode, blend, isPremultiplied,
+ &mDrawTextureVertices[0].position[0], &mDrawTextureVertices[0].texture[0], NULL);
+}
+
+void OpenGLRenderer::drawTextureMesh(float left, float top, float right, float bottom,
+ GLuint texture, float alpha, SkXfermode::Mode mode, bool blend, bool isPremultiplied,
+ GLvoid* vertices, GLvoid* texCoords, GLvoid* indices, GLsizei elementsCount) {
mModelView.loadTranslate(left, top, 0.0f);
mModelView.scale(right - left, bottom - top, 1.0f);
@@ -560,20 +670,21 @@ void OpenGLRenderer::drawTextureRect(float left, float top, float right, float b
glActiveTexture(GL_TEXTURE0);
glUniform1i(mDrawTextureShader->sampler, 0);
- const GLvoid* p = &mDrawTextureVertices[0].position[0];
- const GLvoid* t = &mDrawTextureVertices[0].texture[0];
-
glEnableVertexAttribArray(mDrawTextureShader->position);
glVertexAttribPointer(mDrawTextureShader->position, 2, GL_FLOAT, GL_FALSE,
- gDrawTextureVertexStride, p);
+ gDrawTextureVertexStride, vertices);
glEnableVertexAttribArray(mDrawTextureShader->texCoords);
glVertexAttribPointer(mDrawTextureShader->texCoords, 2, GL_FLOAT, GL_FALSE,
- gDrawTextureVertexStride, t);
+ gDrawTextureVertexStride, texCoords);
glVertexAttrib4f(mDrawTextureShader->color, 1.0f, 1.0f, 1.0f, alpha);
- glDrawArrays(GL_TRIANGLE_STRIP, 0, gDrawTextureVertexCount);
+ if (!indices) {
+ glDrawArrays(GL_TRIANGLE_STRIP, 0, gDrawTextureVertexCount);
+ } else {
+ glDrawElements(GL_TRIANGLES, elementsCount, GL_UNSIGNED_SHORT, indices);
+ }
glDisableVertexAttribArray(mDrawTextureShader->position);
glDisableVertexAttribArray(mDrawTextureShader->texCoords);
diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h
index 9da4b8e..b46e9d3 100644
--- a/libs/hwui/OpenGLRenderer.h
+++ b/libs/hwui/OpenGLRenderer.h
@@ -32,10 +32,10 @@
#include "Program.h"
#include "Rect.h"
#include "Snapshot.h"
-#include "Texture.h"
-#include "Layer.h"
#include "TextureCache.h"
#include "LayerCache.h"
+#include "PatchCache.h"
+#include "Vertex.h"
namespace android {
namespace uirenderer {
@@ -45,22 +45,6 @@ namespace uirenderer {
///////////////////////////////////////////////////////////////////////////////
/**
- * Simple structure to describe a vertex with a position.
- * This is used to draw filled rectangles without a texture.
- */
-struct SimpleVertex {
- float position[2];
-}; // struct SimpleVertex
-
-/**
- * Simple structure to describe a vertex with a position and a texture.
- */
-struct TextureVertex {
- float position[2];
- float texture[2];
-}; // struct TextureVertex
-
-/**
* Structure mapping Skia xfermodes to OpenGL blending factors.
*/
struct Blender {
@@ -198,6 +182,13 @@ private:
float alpha, SkXfermode::Mode mode, bool blend, bool isPremultiplied = false);
/**
+ * TODO: documentation
+ */
+ void drawTextureMesh(float left, float top, float right, float bottom, GLuint texture,
+ float alpha, SkXfermode::Mode mode, bool blend, bool isPremultiplied,
+ GLvoid* vertices, GLvoid* texCoords, GLvoid* indices, GLsizei elementsCount = 0);
+
+ /**
* Resets the texture coordinates stored in mDrawTextureVertices. Setting the values
* back to default is achieved by calling:
*
@@ -220,6 +211,12 @@ private:
*/
inline void getAlphaAndMode(const SkPaint* paint, int* alpha, SkXfermode::Mode* mode);
+ /**
+ * TODO: documentation
+ */
+ inline void generateVertices(TextureVertex* vertex, float y, float v, const int32_t xDivs[],
+ uint32_t xCount, float xStretch, float xStretchTex, float width, float widthTex);
+
// Dimensions of the drawing surface
int mWidth, mHeight;
@@ -243,9 +240,9 @@ private:
// Used to draw textured quads
TextureVertex mDrawTextureVertices[4];
- // Used to cache all drawBitmap textures
TextureCache mTextureCache;
LayerCache mLayerCache;
+ PatchCache mPatchCache;
}; // class OpenGLRenderer
}; // namespace uirenderer
diff --git a/libs/hwui/Patch.h b/libs/hwui/Patch.h
new file mode 100644
index 0000000..c6af18a
--- /dev/null
+++ b/libs/hwui/Patch.h
@@ -0,0 +1,129 @@
+/*
+ * 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_UI_PATCH_H
+#define ANDROID_UI_PATCH_H
+
+#include <sys/types.h>
+
+#include <cstring>
+
+#include "Vertex.h"
+
+namespace android {
+namespace uirenderer {
+
+/**
+ * Description of a patch.
+ */
+struct PatchDescription {
+ PatchDescription(): xCount(0), yCount(0) { }
+ PatchDescription(const uint32_t xCount, const uint32_t yCount):
+ xCount(xCount), yCount(yCount) { }
+ PatchDescription(const PatchDescription& description):
+ xCount(description.xCount), yCount(description.yCount) { }
+
+ uint32_t xCount;
+ uint32_t yCount;
+
+ bool operator<(const PatchDescription& rhs) const {
+ if (xCount == rhs.xCount) {
+ return yCount < rhs.yCount;
+ }
+ return xCount < rhs.xCount;
+ }
+
+ bool operator==(const PatchDescription& rhs) const {
+ return xCount == rhs.xCount && yCount == rhs.yCount;
+ }
+}; // struct PatchDescription
+
+/**
+ * An OpenGL patch. This contains an array of vertices and an array of
+ * indices to render the vertices.
+ */
+struct Patch {
+ Patch(const uint32_t xCount, const uint32_t yCount): xCount(xCount + 2), yCount(yCount + 2) {
+ verticesCount = (xCount + 2) * (yCount + 2);
+ vertices = new TextureVertex[verticesCount];
+
+ // 2 triangles per patch, 3 vertices per triangle
+ indicesCount = (xCount + 1) * (yCount + 1) * 2 * 3;
+ indices = new uint16_t[indicesCount];
+
+ const uint32_t xNum = xCount + 1;
+ const uint32_t yNum = yCount + 1;
+
+ uint16_t* startIndices = indices;
+ uint32_t n = 0;
+ for (uint32_t y = 0; y < yNum; y++) {
+ for (uint32_t x = 0; x < xNum; x++) {
+ *startIndices++ = n;
+ *startIndices++ = n + 1;
+ *startIndices++ = n + xNum + 2;
+
+ *startIndices++ = n;
+ *startIndices++ = n + xNum + 2;
+ *startIndices++ = n + xNum + 1;
+
+ n += 1;
+ }
+ n += 1;
+ }
+ }
+
+ ~Patch() {
+ delete indices;
+ delete vertices;
+ }
+
+ void dump() {
+ LOGD("Vertices [");
+ for (uint32_t y = 0; y < yCount; y++) {
+ char buffer[512];
+ buffer[0] = '\0';
+ uint32_t offset = 0;
+ for (uint32_t x = 0; x < xCount; x++) {
+ TextureVertex* v = &vertices[y * xCount + x];
+ offset += sprintf(&buffer[offset], " (%.4f,%.4f)-(%.4f,%.4f)",
+ v->position[0], v->position[1], v->texture[0], v->texture[1]);
+ }
+ LOGD(" [%s ]", buffer);
+ }
+ LOGD("]\nIndices [ ");
+ char buffer[4096];
+ buffer[0] = '\0';
+ uint32_t offset = 0;
+ for (uint32_t i = 0; i < indicesCount; i++) {
+ offset += sprintf(&buffer[offset], "%d ", indices[i]);
+ }
+ LOGD(" %s\n]", buffer);
+ }
+
+ uint32_t xCount;
+ uint32_t yCount;
+
+ uint16_t* indices;
+ uint32_t indicesCount;
+
+ TextureVertex* vertices;
+ uint32_t verticesCount;
+}; // struct Patch
+
+}; // namespace uirenderer
+}; // namespace android
+
+#endif // ANDROID_UI_PATCH_H
diff --git a/libs/hwui/PatchCache.cpp b/libs/hwui/PatchCache.cpp
new file mode 100644
index 0000000..694e3fd
--- /dev/null
+++ b/libs/hwui/PatchCache.cpp
@@ -0,0 +1,72 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "OpenGLRenderer"
+
+#include <utils/Log.h>
+#include <utils/ResourceTypes.h>
+
+#include "PatchCache.h"
+
+namespace android {
+namespace uirenderer {
+
+///////////////////////////////////////////////////////////////////////////////
+// Constructors/destructor
+///////////////////////////////////////////////////////////////////////////////
+
+PatchCache::PatchCache(uint32_t maxEntries): mCache(maxEntries) {
+}
+
+PatchCache::~PatchCache() {
+ clear();
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Callbacks
+///////////////////////////////////////////////////////////////////////////////
+
+void PatchCache::operator()(PatchDescription& description, Patch*& mesh) {
+ if (mesh) delete mesh;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Caching
+///////////////////////////////////////////////////////////////////////////////
+
+void PatchCache::clear() {
+ mCache.setOnEntryRemovedListener(this);
+ mCache.clear();
+ mCache.setOnEntryRemovedListener(NULL);
+}
+
+Patch* PatchCache::get(const Res_png_9patch* patch) {
+ const uint32_t width = patch->numXDivs;
+ const uint32_t height = patch->numYDivs;
+ const PatchDescription description(width, height);
+
+ Patch* mesh = mCache.get(description);
+ if (!mesh) {
+ PATCH_LOGD("Creating new patch mesh, w=%d h=%d", width, height);
+ mesh = new Patch(width, height);
+ mCache.put(description, mesh);
+ }
+
+ return mesh;
+}
+
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/PatchCache.h b/libs/hwui/PatchCache.h
new file mode 100644
index 0000000..de95087
--- /dev/null
+++ b/libs/hwui/PatchCache.h
@@ -0,0 +1,65 @@
+/*
+ * 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_UI_PATCH_CACHE_H
+#define ANDROID_UI_PATCH_CACHE_H
+
+#include "Patch.h"
+#include "GenerationCache.h"
+
+namespace android {
+namespace uirenderer {
+
+///////////////////////////////////////////////////////////////////////////////
+// Defines
+///////////////////////////////////////////////////////////////////////////////
+
+// Debug
+#define DEBUG_PATCHES 0
+
+// Debug
+#if DEBUG_PATCHES
+ #define PATCH_LOGD(...) LOGD(__VA_ARGS__)
+#else
+ #define PATCH_LOGD(...)
+#endif
+
+///////////////////////////////////////////////////////////////////////////////
+// Cache
+///////////////////////////////////////////////////////////////////////////////
+
+class PatchCache: public OnEntryRemoved<PatchDescription, Patch*> {
+public:
+ PatchCache(uint32_t maxCapacity);
+ ~PatchCache();
+
+ /**
+ * Used as a callback when an entry is removed from the cache.
+ * Do not invoke directly.
+ */
+ void operator()(PatchDescription& description, Patch*& mesh);
+
+ Patch* get(const Res_png_9patch* patch);
+ void clear();
+
+private:
+ GenerationCache<PatchDescription, Patch*> mCache;
+}; // class PatchCache
+
+}; // namespace uirenderer
+}; // namespace android
+
+#endif // ANDROID_UI_PATCH_CACHE_H
diff --git a/libs/hwui/Vertex.h b/libs/hwui/Vertex.h
new file mode 100644
index 0000000..208d2a8
--- /dev/null
+++ b/libs/hwui/Vertex.h
@@ -0,0 +1,49 @@
+/*
+ * 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_UI_VERTEX_H
+#define ANDROID_UI_VERTEX_H
+
+namespace android {
+namespace uirenderer {
+
+/**
+ * Simple structure to describe a vertex with a position.
+ * This is used to draw filled rectangles without a texture.
+ */
+struct SimpleVertex {
+ float position[2];
+}; // struct SimpleVertex
+
+/**
+ * Simple structure to describe a vertex with a position and a texture.
+ */
+struct TextureVertex {
+ float position[2];
+ float texture[2];
+
+ static inline void set(TextureVertex* vertex, float x, float y, float u, float v) {
+ vertex[0].position[0] = x;
+ vertex[0].position[1] = y;
+ vertex[0].texture[0] = u;
+ vertex[0].texture[1] = v;
+ }
+}; // struct TextureVertex
+
+}; // namespace uirenderer
+}; // namespace android
+
+#endif // ANDROID_UI_VERTEX_H
diff --git a/tests/HwAccelerationTest/AndroidManifest.xml b/tests/HwAccelerationTest/AndroidManifest.xml
index 79eed4e..e09e70f 100644
--- a/tests/HwAccelerationTest/AndroidManifest.xml
+++ b/tests/HwAccelerationTest/AndroidManifest.xml
@@ -69,6 +69,15 @@
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
+
+ <activity
+ android:name="NinePatchesActivity"
+ android:label="_9patch">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
</application>
</manifest>
diff --git a/tests/HwAccelerationTest/src/com/google/android/test/hwui/NinePatchesActivity.java b/tests/HwAccelerationTest/src/com/google/android/test/hwui/NinePatchesActivity.java
new file mode 100644
index 0000000..dc8fbcc
--- /dev/null
+++ b/tests/HwAccelerationTest/src/com/google/android/test/hwui/NinePatchesActivity.java
@@ -0,0 +1,40 @@
+/*
+ * 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.
+ */
+
+package com.google.android.test.hwui;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.Gravity;
+import android.widget.Button;
+import android.widget.FrameLayout;
+
+@SuppressWarnings({"UnusedDeclaration"})
+public class NinePatchesActivity extends Activity {
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ FrameLayout layout = new FrameLayout(this);
+ Button b = new Button(this);
+ b.setLayoutParams(new FrameLayout.LayoutParams(FrameLayout.LayoutParams.WRAP_CONTENT,
+ FrameLayout.LayoutParams.WRAP_CONTENT, Gravity.CENTER));
+ b.setText("9 patches");
+ layout.addView(b);
+
+ setContentView(layout);
+ }
+}