Remove direct dependency of external/skia on frameworks/native

Moves all code that needs to link with libgui or libui into
frameworks/native/hwui/utils/TestWindowContext. This allows us to
run Skia automated tests against a HWUI backend to watch for
performance or correctness regressions on Android.

BUG=23556017
TEST=After this change, we can remove libui and frameworks/native/include
from external/skia/Android.mk
R=djsollen@google.com

Change-Id: I6f02a5ff98101e448606a1e892686e2c648b6c8a
diff --git a/libs/hwui/utils/TestWindowContext.cpp b/libs/hwui/utils/TestWindowContext.cpp
new file mode 100644
index 0000000..84aae75
--- /dev/null
+++ b/libs/hwui/utils/TestWindowContext.cpp
@@ -0,0 +1,209 @@
+/*
+ * Copyright (C) 2015 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.
+ */
+#include "TestWindowContext.h"
+
+#include "AnimationContext.h"
+#include "DisplayListCanvas.h"
+#include "IContextFactory.h"
+#include "RenderNode.h"
+#include "SkTypes.h"
+#include "gui/BufferQueue.h"
+#include "gui/CpuConsumer.h"
+#include "gui/IGraphicBufferConsumer.h"
+#include "gui/IGraphicBufferProducer.h"
+#include "gui/Surface.h"
+#include "renderthread/RenderProxy.h"
+
+
+namespace {
+
+/**
+ * Helper class for setting up android::uirenderer::renderthread::RenderProxy.
+ */
+class ContextFactory : public android::uirenderer::IContextFactory {
+public:
+    android::uirenderer::AnimationContext* createAnimationContext
+        (android::uirenderer::renderthread::TimeLord& clock) override {
+        return new android::uirenderer::AnimationContext(clock);
+    }
+};
+
+} // anonymous namespace
+
+namespace android {
+namespace uirenderer {
+
+/**
+  Android strong pointers (android::sp) can't hold forward-declared classes,
+  so we have to use pointer-to-implementation here if we want to hide the
+  details from our non-framework users.
+*/
+
+class TestWindowContext::TestWindowData {
+
+public:
+
+    TestWindowData(SkISize size) : mSize(size) {
+        android::BufferQueue::createBufferQueue(&mProducer, &mConsumer);
+        mCpuConsumer = new android::CpuConsumer(mConsumer, 1);
+        mCpuConsumer->setName(android::String8("TestWindowContext"));
+        mCpuConsumer->setDefaultBufferSize(mSize.width(), mSize.height());
+        mAndroidSurface = new android::Surface(mProducer);
+        native_window_set_buffers_dimensions(mAndroidSurface.get(),
+                                             mSize.width(), mSize.height());
+        native_window_set_buffers_format(mAndroidSurface.get(),
+                                         android::PIXEL_FORMAT_RGBA_8888);
+        native_window_set_usage(mAndroidSurface.get(),
+                                GRALLOC_USAGE_SW_READ_OFTEN |
+                                GRALLOC_USAGE_SW_WRITE_NEVER |
+                                GRALLOC_USAGE_HW_RENDER);
+        mRootNode.reset(new android::uirenderer::RenderNode());
+        mRootNode->incStrong(nullptr);
+        mRootNode->mutateStagingProperties().setLeftTopRightBottom
+            (0, 0, mSize.width(), mSize.height());
+        mRootNode->mutateStagingProperties().setClipToBounds(false);
+        mRootNode->setPropertyFieldsDirty(android::uirenderer::RenderNode::GENERIC);
+        ContextFactory factory;
+        mProxy.reset
+            (new android::uirenderer::renderthread::RenderProxy(false,
+                                                                mRootNode.get(),
+                                                                &factory));
+        mProxy->loadSystemProperties();
+        mProxy->initialize(mAndroidSurface.get());
+        float lightX = mSize.width() / 2.0f;
+        android::uirenderer::Vector3 lightVector { lightX, -200.0f, 800.0f };
+        mProxy->setup(mSize.width(), mSize.height(), 800.0f,
+                             255 * 0.075f, 255 * 0.15f);
+        mProxy->setLightCenter(lightVector);
+        mCanvas.reset(new
+            android::uirenderer::DisplayListCanvas(mSize.width(),
+                                                   mSize.height()));
+    }
+
+    SkCanvas* prepareToDraw() {
+        //mCanvas->reset(mSize.width(), mSize.height());
+        mCanvas->clipRect(0, 0, mSize.width(), mSize.height(),
+                               SkRegion::Op::kReplace_Op);
+        return mCanvas->asSkCanvas();
+    }
+
+    void finishDrawing() {
+        mRootNode->setStagingDisplayList(mCanvas->finishRecording());
+        mProxy->syncAndDrawFrame();
+        // Surprisingly, calling mProxy->fence() here appears to make no difference to
+        // the timings we record.
+    }
+
+    void fence() {
+        mProxy->fence();
+    }
+
+    bool capturePixels(SkBitmap* bmp) {
+        SkImageInfo destinationConfig =
+            SkImageInfo::Make(mSize.width(), mSize.height(),
+                              kRGBA_8888_SkColorType, kPremul_SkAlphaType);
+        bmp->allocPixels(destinationConfig);
+        sk_memset32((uint32_t*) bmp->getPixels(), SK_ColorRED,
+                    mSize.width() * mSize.height());
+
+        android::CpuConsumer::LockedBuffer nativeBuffer;
+        android::status_t retval = mCpuConsumer->lockNextBuffer(&nativeBuffer);
+        if (retval == android::BAD_VALUE) {
+            SkDebugf("write_canvas_png() got no buffer; returning transparent");
+            // No buffer ready to read - commonly triggered by dm sending us
+            // a no-op source, or calling code that doesn't do anything on this
+            // backend.
+            bmp->eraseColor(SK_ColorTRANSPARENT);
+            return false;
+        } else if (retval) {
+            SkDebugf("Failed to lock buffer to read pixels: %d.", retval);
+            return false;
+        }
+
+        // Move the pixels into the destination SkBitmap
+
+        SK_ALWAYSBREAK(nativeBuffer.format == android::PIXEL_FORMAT_RGBA_8888 &&
+                       "Native buffer not RGBA!");
+        SkImageInfo nativeConfig =
+            SkImageInfo::Make(nativeBuffer.width, nativeBuffer.height,
+                              kRGBA_8888_SkColorType, kPremul_SkAlphaType);
+
+        // Android stride is in pixels, Skia stride is in bytes
+        SkBitmap nativeWrapper;
+        bool success =
+            nativeWrapper.installPixels(nativeConfig, nativeBuffer.data, nativeBuffer.stride * 4);
+        if (!success) {
+            SkDebugf("Failed to wrap HWUI buffer in a SkBitmap");
+            return false;
+        }
+
+        SK_ALWAYSBREAK(bmp->colorType() == kRGBA_8888_SkColorType &&
+                       "Destination buffer not RGBA!");
+        success =
+            nativeWrapper.readPixels(destinationConfig, bmp->getPixels(), bmp->rowBytes(), 0, 0);
+        if (!success) {
+            SkDebugf("Failed to extract pixels from HWUI buffer");
+            return false;
+        }
+
+        mCpuConsumer->unlockBuffer(nativeBuffer);
+
+        return true;
+    }
+
+private:
+
+    std::unique_ptr<android::uirenderer::RenderNode> mRootNode;
+    std::unique_ptr<android::uirenderer::renderthread::RenderProxy> mProxy;
+    std::unique_ptr<android::uirenderer::DisplayListCanvas> mCanvas;
+    android::sp<android::IGraphicBufferProducer> mProducer;
+    android::sp<android::IGraphicBufferConsumer> mConsumer;
+    android::sp<android::CpuConsumer> mCpuConsumer;
+    android::sp<android::Surface> mAndroidSurface;
+    SkISize mSize;
+};
+
+
+TestWindowContext::TestWindowContext() :
+    mData (nullptr) { }
+
+void TestWindowContext::initialize(int width, int height)  {
+    mData = new TestWindowData(SkISize::Make(width, height));
+}
+
+SkCanvas* TestWindowContext::prepareToDraw() {
+    return mData ? mData->prepareToDraw() : nullptr;
+}
+
+void TestWindowContext::finishDrawing() {
+    if (mData) {
+        mData->finishDrawing();
+    }
+}
+
+void TestWindowContext::fence() {
+    if (mData) {
+        mData->fence();
+    }
+}
+
+bool TestWindowContext::capturePixels(SkBitmap* bmp) {
+    return mData ? mData->capturePixels(bmp) : false;
+}
+
+} // namespace uirenderer
+} // namespace android
+