blob: d56693ce70093feaf5d20f4cda82023f581f4581 [file] [log] [blame]
John Reck16c9d6a2015-11-17 15:51:08 -08001/*
2 * Copyright (C) 2015 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "TestUtils.h"
18
Chris Craikd2dfd8f2015-12-16 14:27:20 -080019#include "DeferredLayerUpdater.h"
20#include "LayerRenderer.h"
21
John Recke5da4ef2016-01-14 12:34:46 -080022#include <unistd.h>
23#include <signal.h>
24#include <setjmp.h>
25
John Reck16c9d6a2015-11-17 15:51:08 -080026namespace android {
27namespace uirenderer {
28
29SkColor TestUtils::interpolateColor(float fraction, SkColor start, SkColor end) {
30 int startA = (start >> 24) & 0xff;
31 int startR = (start >> 16) & 0xff;
32 int startG = (start >> 8) & 0xff;
33 int startB = start & 0xff;
34
35 int endA = (end >> 24) & 0xff;
36 int endR = (end >> 16) & 0xff;
37 int endG = (end >> 8) & 0xff;
38 int endB = end & 0xff;
39
40 return (int)((startA + (int)(fraction * (endA - startA))) << 24)
41 | (int)((startR + (int)(fraction * (endR - startR))) << 16)
42 | (int)((startG + (int)(fraction * (endG - startG))) << 8)
43 | (int)((startB + (int)(fraction * (endB - startB))));
44}
45
Chris Craikd2dfd8f2015-12-16 14:27:20 -080046sp<DeferredLayerUpdater> TestUtils::createTextureLayerUpdater(
47 renderthread::RenderThread& renderThread, uint32_t width, uint32_t height,
48 std::function<void(Matrix4*)> transformSetupCallback) {
49 bool isOpaque = true;
50 bool forceFilter = true;
51 GLenum renderTarget = GL_TEXTURE_EXTERNAL_OES;
52
53 Layer* layer = LayerRenderer::createTextureLayer(renderThread.renderState());
54 LayerRenderer::updateTextureLayer(layer, width, height, isOpaque, forceFilter,
55 renderTarget, Matrix4::identity().data);
56 transformSetupCallback(&(layer->getTransform()));
57
58 sp<DeferredLayerUpdater> layerUpdater = new DeferredLayerUpdater(layer);
59 return layerUpdater;
60}
61
Chris Craika1717272015-11-19 13:02:43 -080062void TestUtils::drawTextToCanvas(TestCanvas* canvas, const char* text,
Chris Craik42a54072015-11-24 11:41:54 -080063 const SkPaint& paint, float x, float y) {
64 // drawing text requires GlyphID TextEncoding (which JNI layer would have done)
65 LOG_ALWAYS_FATAL_IF(paint.getTextEncoding() != SkPaint::kGlyphID_TextEncoding,
66 "must use glyph encoding");
Chris Craik42a54072015-11-24 11:41:54 -080067 SkSurfaceProps surfaceProps(0, kUnknown_SkPixelGeometry);
Chris Craikd7448e62015-12-15 10:34:36 -080068 SkAutoGlyphCacheNoGamma autoCache(paint, &surfaceProps, &SkMatrix::I());
Chris Craika1717272015-11-19 13:02:43 -080069
Chris Craik42a54072015-11-24 11:41:54 -080070 float totalAdvance = 0;
71 std::vector<glyph_t> glyphs;
72 std::vector<float> positions;
73 Rect bounds;
74 while (*text != '\0') {
75 SkUnichar unichar = SkUTF8_NextUnichar(&text);
76 glyph_t glyph = autoCache.getCache()->unicharToGlyph(unichar);
77 autoCache.getCache()->unicharToGlyph(unichar);
Chris Craika1717272015-11-19 13:02:43 -080078
Chris Craik42a54072015-11-24 11:41:54 -080079 // push glyph and its relative position
80 glyphs.push_back(glyph);
81 positions.push_back(totalAdvance);
82 positions.push_back(0);
Chris Craika1717272015-11-19 13:02:43 -080083
Chris Craik42a54072015-11-24 11:41:54 -080084 // compute bounds
85 SkGlyph skGlyph = autoCache.getCache()->getUnicharMetrics(unichar);
86 Rect glyphBounds(skGlyph.fWidth, skGlyph.fHeight);
87 glyphBounds.translate(totalAdvance + skGlyph.fLeft, skGlyph.fTop);
88 bounds.unionWith(glyphBounds);
Chris Craika1717272015-11-19 13:02:43 -080089
Chris Craik42a54072015-11-24 11:41:54 -080090 // advance next character
91 SkScalar skWidth;
92 paint.getTextWidths(&glyph, sizeof(glyph), &skWidth, NULL);
93 totalAdvance += skWidth;
94 }
95
96 // apply alignment via x parameter (which JNI layer would have done)
97 if (paint.getTextAlign() == SkPaint::kCenter_Align) {
98 x -= totalAdvance / 2;
99 } else if (paint.getTextAlign() == SkPaint::kRight_Align) {
100 x -= totalAdvance;
101 }
102
103 bounds.translate(x, y);
104
105 // Force left alignment, since alignment offset is already baked in
106 SkPaint alignPaintCopy(paint);
107 alignPaintCopy.setTextAlign(SkPaint::kLeft_Align);
108 canvas->drawText(glyphs.data(), positions.data(), glyphs.size(), alignPaintCopy, x, y,
109 bounds.left, bounds.top, bounds.right, bounds.bottom, totalAdvance);
Chris Craika1717272015-11-19 13:02:43 -0800110}
111
Chris Craikd7448e62015-12-15 10:34:36 -0800112void TestUtils::drawTextToCanvas(TestCanvas* canvas, const char* text,
113 const SkPaint& paint, const SkPath& path) {
114 // drawing text requires GlyphID TextEncoding (which JNI layer would have done)
115 LOG_ALWAYS_FATAL_IF(paint.getTextEncoding() != SkPaint::kGlyphID_TextEncoding,
116 "must use glyph encoding");
117 SkSurfaceProps surfaceProps(0, kUnknown_SkPixelGeometry);
118 SkAutoGlyphCacheNoGamma autoCache(paint, &surfaceProps, &SkMatrix::I());
119
120 std::vector<glyph_t> glyphs;
121 while (*text != '\0') {
122 SkUnichar unichar = SkUTF8_NextUnichar(&text);
123 glyphs.push_back(autoCache.getCache()->unicharToGlyph(unichar));
124 }
125 canvas->drawTextOnPath(glyphs.data(), glyphs.size(), path, 0, 0, paint);
126}
127
John Recke5da4ef2016-01-14 12:34:46 -0800128static void defaultCrashHandler() {
129 fprintf(stderr, "RenderThread crashed!");
130}
131
132static jmp_buf gErrJmpBuff;
133static std::function<void()> gCrashHandler = defaultCrashHandler;
134
135static void signalHandler(int sig) {
136 longjmp(gErrJmpBuff, 1);
137}
138
139void TestUtils::setRenderThreadCrashHandler(std::function<void()> crashHandler) {
140 gCrashHandler = crashHandler;
141}
142
143void TestUtils::TestTask::run() {
144 struct sigaction act;
145 memset(&act, 0, sizeof(act));
146 act.sa_handler = signalHandler;
147
148 if (setjmp(gErrJmpBuff)) {
149 gCrashHandler();
150 return;
151 }
152
153 sigaction(SIGABRT, &act, nullptr);
154
155
156 // RenderState only valid once RenderThread is running, so queried here
157 RenderState& renderState = renderthread::RenderThread::getInstance().renderState();
158
159 renderState.onGLContextCreated();
160 rtCallback(renderthread::RenderThread::getInstance());
161 renderState.onGLContextDestroyed();
162}
163
John Reck16c9d6a2015-11-17 15:51:08 -0800164} /* namespace uirenderer */
165} /* namespace android */