TestUtils.cpp revision e8c3c813b0e3ac98304b17a751ce6e436e252bd9
116c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck/*
216c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck * Copyright (C) 2015 The Android Open Source Project
316c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck *
416c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck * Licensed under the Apache License, Version 2.0 (the "License");
516c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck * you may not use this file except in compliance with the License.
616c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck * You may obtain a copy of the License at
716c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck *
816c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck *      http://www.apache.org/licenses/LICENSE-2.0
916c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck *
1016c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck * Unless required by applicable law or agreed to in writing, software
1116c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck * distributed under the License is distributed on an "AS IS" BASIS,
1216c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1316c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck * See the License for the specific language governing permissions and
1416c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck * limitations under the License.
1516c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck */
1616c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck
1716c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck#include "TestUtils.h"
1816c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck
19d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik#include "DeferredLayerUpdater.h"
20d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik#include "LayerRenderer.h"
21d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik
22e5da4ef971258193cd1e89737a12b95b6ac244bbJohn Reck#include <unistd.h>
23e5da4ef971258193cd1e89737a12b95b6ac244bbJohn Reck#include <signal.h>
24e5da4ef971258193cd1e89737a12b95b6ac244bbJohn Reck
2516c9d6a92e1b86d448c00c52a1630f3e71e6df76John Recknamespace android {
2616c9d6a92e1b86d448c00c52a1630f3e71e6df76John Recknamespace uirenderer {
2716c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck
2816c9d6a92e1b86d448c00c52a1630f3e71e6df76John ReckSkColor TestUtils::interpolateColor(float fraction, SkColor start, SkColor end) {
2916c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck    int startA = (start >> 24) & 0xff;
3016c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck    int startR = (start >> 16) & 0xff;
3116c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck    int startG = (start >> 8) & 0xff;
3216c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck    int startB = start & 0xff;
3316c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck
3416c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck    int endA = (end >> 24) & 0xff;
3516c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck    int endR = (end >> 16) & 0xff;
3616c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck    int endG = (end >> 8) & 0xff;
3716c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck    int endB = end & 0xff;
3816c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck
3916c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck    return (int)((startA + (int)(fraction * (endA - startA))) << 24)
4016c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck            | (int)((startR + (int)(fraction * (endR - startR))) << 16)
4116c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck            | (int)((startG + (int)(fraction * (endG - startG))) << 8)
4216c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck            | (int)((startB + (int)(fraction * (endB - startB))));
4316c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck}
4416c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck
45d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craiksp<DeferredLayerUpdater> TestUtils::createTextureLayerUpdater(
46d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik        renderthread::RenderThread& renderThread, uint32_t width, uint32_t height,
47d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik        std::function<void(Matrix4*)> transformSetupCallback) {
48d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik    bool isOpaque = true;
49d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik    bool forceFilter = true;
50d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik    GLenum renderTarget = GL_TEXTURE_EXTERNAL_OES;
51d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik
52d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik    Layer* layer = LayerRenderer::createTextureLayer(renderThread.renderState());
53d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik    LayerRenderer::updateTextureLayer(layer, width, height, isOpaque, forceFilter,
54d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik            renderTarget, Matrix4::identity().data);
55d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik    transformSetupCallback(&(layer->getTransform()));
56d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik
57d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik    sp<DeferredLayerUpdater> layerUpdater = new DeferredLayerUpdater(layer);
58d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik    return layerUpdater;
59d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik}
60d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik
61e8c3c813b0e3ac98304b17a751ce6e436e252bd9Chris Craikvoid TestUtils::layoutTextUnscaled(const SkPaint& paint, const char* text,
62e8c3c813b0e3ac98304b17a751ce6e436e252bd9Chris Craik        std::vector<glyph_t>* outGlyphs, std::vector<float>* outPositions,
63e8c3c813b0e3ac98304b17a751ce6e436e252bd9Chris Craik        float* outTotalAdvance, Rect* outBounds) {
64e8c3c813b0e3ac98304b17a751ce6e436e252bd9Chris Craik    Rect bounds;
65e8c3c813b0e3ac98304b17a751ce6e436e252bd9Chris Craik    float totalAdvance = 0;
6642a5407f2c6403ea7aa7a64eaf19948dc4050df5Chris Craik    SkSurfaceProps surfaceProps(0, kUnknown_SkPixelGeometry);
67d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik    SkAutoGlyphCacheNoGamma autoCache(paint, &surfaceProps, &SkMatrix::I());
6842a5407f2c6403ea7aa7a64eaf19948dc4050df5Chris Craik    while (*text != '\0') {
6942a5407f2c6403ea7aa7a64eaf19948dc4050df5Chris Craik        SkUnichar unichar = SkUTF8_NextUnichar(&text);
7042a5407f2c6403ea7aa7a64eaf19948dc4050df5Chris Craik        glyph_t glyph = autoCache.getCache()->unicharToGlyph(unichar);
7142a5407f2c6403ea7aa7a64eaf19948dc4050df5Chris Craik        autoCache.getCache()->unicharToGlyph(unichar);
72a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik
7342a5407f2c6403ea7aa7a64eaf19948dc4050df5Chris Craik        // push glyph and its relative position
74e8c3c813b0e3ac98304b17a751ce6e436e252bd9Chris Craik        outGlyphs->push_back(glyph);
75e8c3c813b0e3ac98304b17a751ce6e436e252bd9Chris Craik        outPositions->push_back(totalAdvance);
76e8c3c813b0e3ac98304b17a751ce6e436e252bd9Chris Craik        outPositions->push_back(0);
77a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik
7842a5407f2c6403ea7aa7a64eaf19948dc4050df5Chris Craik        // compute bounds
7942a5407f2c6403ea7aa7a64eaf19948dc4050df5Chris Craik        SkGlyph skGlyph = autoCache.getCache()->getUnicharMetrics(unichar);
8042a5407f2c6403ea7aa7a64eaf19948dc4050df5Chris Craik        Rect glyphBounds(skGlyph.fWidth, skGlyph.fHeight);
8142a5407f2c6403ea7aa7a64eaf19948dc4050df5Chris Craik        glyphBounds.translate(totalAdvance + skGlyph.fLeft, skGlyph.fTop);
8242a5407f2c6403ea7aa7a64eaf19948dc4050df5Chris Craik        bounds.unionWith(glyphBounds);
83a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik
8442a5407f2c6403ea7aa7a64eaf19948dc4050df5Chris Craik        // advance next character
8542a5407f2c6403ea7aa7a64eaf19948dc4050df5Chris Craik        SkScalar skWidth;
8642a5407f2c6403ea7aa7a64eaf19948dc4050df5Chris Craik        paint.getTextWidths(&glyph, sizeof(glyph), &skWidth, NULL);
8742a5407f2c6403ea7aa7a64eaf19948dc4050df5Chris Craik        totalAdvance += skWidth;
8842a5407f2c6403ea7aa7a64eaf19948dc4050df5Chris Craik    }
89e8c3c813b0e3ac98304b17a751ce6e436e252bd9Chris Craik    *outBounds = bounds;
90e8c3c813b0e3ac98304b17a751ce6e436e252bd9Chris Craik    *outTotalAdvance = totalAdvance;
91e8c3c813b0e3ac98304b17a751ce6e436e252bd9Chris Craik}
92e8c3c813b0e3ac98304b17a751ce6e436e252bd9Chris Craik
93e8c3c813b0e3ac98304b17a751ce6e436e252bd9Chris Craikvoid TestUtils::drawTextToCanvas(TestCanvas* canvas, const char* text,
94e8c3c813b0e3ac98304b17a751ce6e436e252bd9Chris Craik        const SkPaint& paint, float x, float y) {
95e8c3c813b0e3ac98304b17a751ce6e436e252bd9Chris Craik    // drawing text requires GlyphID TextEncoding (which JNI layer would have done)
96e8c3c813b0e3ac98304b17a751ce6e436e252bd9Chris Craik    LOG_ALWAYS_FATAL_IF(paint.getTextEncoding() != SkPaint::kGlyphID_TextEncoding,
97e8c3c813b0e3ac98304b17a751ce6e436e252bd9Chris Craik            "must use glyph encoding");
98e8c3c813b0e3ac98304b17a751ce6e436e252bd9Chris Craik    SkSurfaceProps surfaceProps(0, kUnknown_SkPixelGeometry);
99e8c3c813b0e3ac98304b17a751ce6e436e252bd9Chris Craik    SkAutoGlyphCacheNoGamma autoCache(paint, &surfaceProps, &SkMatrix::I());
100e8c3c813b0e3ac98304b17a751ce6e436e252bd9Chris Craik
101e8c3c813b0e3ac98304b17a751ce6e436e252bd9Chris Craik    std::vector<glyph_t> glyphs;
102e8c3c813b0e3ac98304b17a751ce6e436e252bd9Chris Craik    std::vector<float> positions;
103e8c3c813b0e3ac98304b17a751ce6e436e252bd9Chris Craik    float totalAdvance;
104e8c3c813b0e3ac98304b17a751ce6e436e252bd9Chris Craik    Rect bounds;
105e8c3c813b0e3ac98304b17a751ce6e436e252bd9Chris Craik    layoutTextUnscaled(paint, text, &glyphs, &positions, &totalAdvance, &bounds);
10642a5407f2c6403ea7aa7a64eaf19948dc4050df5Chris Craik
10742a5407f2c6403ea7aa7a64eaf19948dc4050df5Chris Craik    // apply alignment via x parameter (which JNI layer would have done)
10842a5407f2c6403ea7aa7a64eaf19948dc4050df5Chris Craik    if (paint.getTextAlign() == SkPaint::kCenter_Align) {
10942a5407f2c6403ea7aa7a64eaf19948dc4050df5Chris Craik        x -= totalAdvance / 2;
11042a5407f2c6403ea7aa7a64eaf19948dc4050df5Chris Craik    } else if (paint.getTextAlign() == SkPaint::kRight_Align) {
11142a5407f2c6403ea7aa7a64eaf19948dc4050df5Chris Craik        x -= totalAdvance;
11242a5407f2c6403ea7aa7a64eaf19948dc4050df5Chris Craik    }
11342a5407f2c6403ea7aa7a64eaf19948dc4050df5Chris Craik
11442a5407f2c6403ea7aa7a64eaf19948dc4050df5Chris Craik    bounds.translate(x, y);
11542a5407f2c6403ea7aa7a64eaf19948dc4050df5Chris Craik
11642a5407f2c6403ea7aa7a64eaf19948dc4050df5Chris Craik    // Force left alignment, since alignment offset is already baked in
11742a5407f2c6403ea7aa7a64eaf19948dc4050df5Chris Craik    SkPaint alignPaintCopy(paint);
11842a5407f2c6403ea7aa7a64eaf19948dc4050df5Chris Craik    alignPaintCopy.setTextAlign(SkPaint::kLeft_Align);
11942a5407f2c6403ea7aa7a64eaf19948dc4050df5Chris Craik    canvas->drawText(glyphs.data(), positions.data(), glyphs.size(), alignPaintCopy, x, y,
12042a5407f2c6403ea7aa7a64eaf19948dc4050df5Chris Craik                bounds.left, bounds.top, bounds.right, bounds.bottom, totalAdvance);
121a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik}
122a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik
123d7448e65e243754f31890baef29dff187dc2e5e5Chris Craikvoid TestUtils::drawTextToCanvas(TestCanvas* canvas, const char* text,
124d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik        const SkPaint& paint, const SkPath& path) {
125d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik    // drawing text requires GlyphID TextEncoding (which JNI layer would have done)
126d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik    LOG_ALWAYS_FATAL_IF(paint.getTextEncoding() != SkPaint::kGlyphID_TextEncoding,
127d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik            "must use glyph encoding");
128d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik    SkSurfaceProps surfaceProps(0, kUnknown_SkPixelGeometry);
129d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik    SkAutoGlyphCacheNoGamma autoCache(paint, &surfaceProps, &SkMatrix::I());
130d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik
131d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik    std::vector<glyph_t> glyphs;
132d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik    while (*text != '\0') {
133d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik        SkUnichar unichar = SkUTF8_NextUnichar(&text);
134d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik        glyphs.push_back(autoCache.getCache()->unicharToGlyph(unichar));
135d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik    }
136d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik    canvas->drawTextOnPath(glyphs.data(), glyphs.size(), path, 0, 0, paint);
137d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik}
138d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik
139e5da4ef971258193cd1e89737a12b95b6ac244bbJohn Reckstatic void defaultCrashHandler() {
140e5da4ef971258193cd1e89737a12b95b6ac244bbJohn Reck    fprintf(stderr, "RenderThread crashed!");
141e5da4ef971258193cd1e89737a12b95b6ac244bbJohn Reck}
142e5da4ef971258193cd1e89737a12b95b6ac244bbJohn Reck
143e5da4ef971258193cd1e89737a12b95b6ac244bbJohn Reckstatic std::function<void()> gCrashHandler = defaultCrashHandler;
144f1dafb5962e798a02417b5a2075b6dcc318561abJohn Reckstatic sighandler_t gPreviousSignalHandler;
145e5da4ef971258193cd1e89737a12b95b6ac244bbJohn Reck
146e5da4ef971258193cd1e89737a12b95b6ac244bbJohn Reckstatic void signalHandler(int sig) {
147f1dafb5962e798a02417b5a2075b6dcc318561abJohn Reck    gCrashHandler();
148f1dafb5962e798a02417b5a2075b6dcc318561abJohn Reck    if (gPreviousSignalHandler) {
149f1dafb5962e798a02417b5a2075b6dcc318561abJohn Reck        gPreviousSignalHandler(sig);
150f1dafb5962e798a02417b5a2075b6dcc318561abJohn Reck    }
151e5da4ef971258193cd1e89737a12b95b6ac244bbJohn Reck}
152e5da4ef971258193cd1e89737a12b95b6ac244bbJohn Reck
153e5da4ef971258193cd1e89737a12b95b6ac244bbJohn Reckvoid TestUtils::setRenderThreadCrashHandler(std::function<void()> crashHandler) {
154e5da4ef971258193cd1e89737a12b95b6ac244bbJohn Reck    gCrashHandler = crashHandler;
155e5da4ef971258193cd1e89737a12b95b6ac244bbJohn Reck}
156e5da4ef971258193cd1e89737a12b95b6ac244bbJohn Reck
157e5da4ef971258193cd1e89737a12b95b6ac244bbJohn Reckvoid TestUtils::TestTask::run() {
158f1dafb5962e798a02417b5a2075b6dcc318561abJohn Reck    gPreviousSignalHandler = signal(SIGABRT, signalHandler);
159e5da4ef971258193cd1e89737a12b95b6ac244bbJohn Reck
160e5da4ef971258193cd1e89737a12b95b6ac244bbJohn Reck    // RenderState only valid once RenderThread is running, so queried here
161e5da4ef971258193cd1e89737a12b95b6ac244bbJohn Reck    RenderState& renderState = renderthread::RenderThread::getInstance().renderState();
162e5da4ef971258193cd1e89737a12b95b6ac244bbJohn Reck
163e5da4ef971258193cd1e89737a12b95b6ac244bbJohn Reck    renderState.onGLContextCreated();
164e5da4ef971258193cd1e89737a12b95b6ac244bbJohn Reck    rtCallback(renderthread::RenderThread::getInstance());
165e5da4ef971258193cd1e89737a12b95b6ac244bbJohn Reck    renderState.onGLContextDestroyed();
166f1dafb5962e798a02417b5a2075b6dcc318561abJohn Reck
167f1dafb5962e798a02417b5a2075b6dcc318561abJohn Reck    // Restore the previous signal handler
168f1dafb5962e798a02417b5a2075b6dcc318561abJohn Reck    signal(SIGABRT, gPreviousSignalHandler);
169e5da4ef971258193cd1e89737a12b95b6ac244bbJohn Reck}
170e5da4ef971258193cd1e89737a12b95b6ac244bbJohn Reck
17116c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck} /* namespace uirenderer */
17216c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck} /* namespace android */
173