1 /* 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 19 #include "hwui/Paint.h" 20 #include "DeferredLayerUpdater.h" 21 22 #include <renderthread/EglManager.h> 23 #include <renderthread/OpenGLPipeline.h> 24 #include <pipeline/skia/SkiaOpenGLPipeline.h> 25 #include <pipeline/skia/SkiaVulkanPipeline.h> 26 #include <renderthread/VulkanManager.h> 27 #include <utils/Unicode.h> 28 #include <SkClipStack.h> 29 30 #include <SkGlyphCache.h> 31 32 namespace android { 33 namespace uirenderer { 34 35 SkColor TestUtils::interpolateColor(float fraction, SkColor start, SkColor end) { 36 int startA = (start >> 24) & 0xff; 37 int startR = (start >> 16) & 0xff; 38 int startG = (start >> 8) & 0xff; 39 int startB = start & 0xff; 40 41 int endA = (end >> 24) & 0xff; 42 int endR = (end >> 16) & 0xff; 43 int endG = (end >> 8) & 0xff; 44 int endB = end & 0xff; 45 46 return (int)((startA + (int)(fraction * (endA - startA))) << 24) 47 | (int)((startR + (int)(fraction * (endR - startR))) << 16) 48 | (int)((startG + (int)(fraction * (endG - startG))) << 8) 49 | (int)((startB + (int)(fraction * (endB - startB)))); 50 } 51 52 sp<DeferredLayerUpdater> TestUtils::createTextureLayerUpdater( 53 renderthread::RenderThread& renderThread) { 54 android::uirenderer::renderthread::IRenderPipeline* pipeline; 55 if (Properties::getRenderPipelineType() == RenderPipelineType::OpenGL) { 56 pipeline = new renderthread::OpenGLPipeline(renderThread); 57 } else if (Properties::getRenderPipelineType() == RenderPipelineType::SkiaGL) { 58 pipeline = new skiapipeline::SkiaOpenGLPipeline(renderThread); 59 } else { 60 pipeline = new skiapipeline::SkiaVulkanPipeline(renderThread); 61 } 62 sp<DeferredLayerUpdater> layerUpdater = pipeline->createTextureLayer(); 63 layerUpdater->apply(); 64 delete pipeline; 65 return layerUpdater; 66 } 67 68 sp<DeferredLayerUpdater> TestUtils::createTextureLayerUpdater( 69 renderthread::RenderThread& renderThread, uint32_t width, uint32_t height, 70 const SkMatrix& transform) { 71 sp<DeferredLayerUpdater> layerUpdater = createTextureLayerUpdater(renderThread); 72 layerUpdater->backingLayer()->getTransform().load(transform); 73 layerUpdater->setSize(width, height); 74 layerUpdater->setTransform(&transform); 75 76 // updateLayer so it's ready to draw 77 layerUpdater->updateLayer(true, Matrix4::identity().data); 78 if (layerUpdater->backingLayer()->getApi() == Layer::Api::OpenGL) { 79 static_cast<GlLayer*>(layerUpdater->backingLayer())->setRenderTarget( 80 GL_TEXTURE_EXTERNAL_OES); 81 } 82 return layerUpdater; 83 } 84 85 void TestUtils::layoutTextUnscaled(const SkPaint& paint, const char* text, 86 std::vector<glyph_t>* outGlyphs, std::vector<float>* outPositions, 87 float* outTotalAdvance, Rect* outBounds) { 88 Rect bounds; 89 float totalAdvance = 0; 90 SkSurfaceProps surfaceProps(0, kUnknown_SkPixelGeometry); 91 SkAutoGlyphCacheNoGamma autoCache(paint, &surfaceProps, &SkMatrix::I()); 92 while (*text != '\0') { 93 size_t nextIndex = 0; 94 int32_t unichar = utf32_from_utf8_at(text, 4, 0, &nextIndex); 95 text += nextIndex; 96 97 glyph_t glyph = autoCache.getCache()->unicharToGlyph(unichar); 98 autoCache.getCache()->unicharToGlyph(unichar); 99 100 // push glyph and its relative position 101 outGlyphs->push_back(glyph); 102 outPositions->push_back(totalAdvance); 103 outPositions->push_back(0); 104 105 // compute bounds 106 SkGlyph skGlyph = autoCache.getCache()->getUnicharMetrics(unichar); 107 Rect glyphBounds(skGlyph.fWidth, skGlyph.fHeight); 108 glyphBounds.translate(totalAdvance + skGlyph.fLeft, skGlyph.fTop); 109 bounds.unionWith(glyphBounds); 110 111 // advance next character 112 SkScalar skWidth; 113 paint.getTextWidths(&glyph, sizeof(glyph), &skWidth, NULL); 114 totalAdvance += skWidth; 115 } 116 *outBounds = bounds; 117 *outTotalAdvance = totalAdvance; 118 } 119 120 121 void TestUtils::drawUtf8ToCanvas(Canvas* canvas, const char* text, 122 const SkPaint& paint, float x, float y) { 123 auto utf16 = asciiToUtf16(text); 124 canvas->drawText(utf16.get(), 0, strlen(text), strlen(text), x, y, 0, paint, nullptr); 125 } 126 127 void TestUtils::drawUtf8ToCanvas(Canvas* canvas, const char* text, 128 const SkPaint& paint, const SkPath& path) { 129 auto utf16 = asciiToUtf16(text); 130 canvas->drawTextOnPath(utf16.get(), strlen(text), 0, path, 0, 0, paint, nullptr); 131 } 132 133 void TestUtils::TestTask::run() { 134 // RenderState only valid once RenderThread is running, so queried here 135 renderthread::RenderThread& renderThread = renderthread::RenderThread::getInstance(); 136 if (Properties::getRenderPipelineType() == RenderPipelineType::SkiaVulkan) { 137 renderThread.vulkanManager().initialize(); 138 } else { 139 renderThread.eglManager().initialize(); 140 } 141 142 rtCallback(renderThread); 143 144 if (Properties::getRenderPipelineType() == RenderPipelineType::SkiaVulkan) { 145 renderThread.vulkanManager().destroy(); 146 } else { 147 renderThread.renderState().flush(Caches::FlushMode::Full); 148 renderThread.eglManager().destroy(); 149 } 150 } 151 152 std::unique_ptr<uint16_t[]> TestUtils::asciiToUtf16(const char* str) { 153 const int length = strlen(str); 154 std::unique_ptr<uint16_t[]> utf16(new uint16_t[length]); 155 for (int i = 0; i < length; i++) { 156 utf16.get()[i] = str[i]; 157 } 158 return utf16; 159 } 160 161 SkColor TestUtils::getColor(const sk_sp<SkSurface>& surface, int x, int y) { 162 SkPixmap pixmap; 163 if (!surface->peekPixels(&pixmap)) { 164 return 0; 165 } 166 switch (pixmap.colorType()) { 167 case kGray_8_SkColorType: { 168 const uint8_t* addr = pixmap.addr8(x, y); 169 return SkColorSetRGB(*addr, *addr, *addr); 170 } 171 case kAlpha_8_SkColorType: { 172 const uint8_t* addr = pixmap.addr8(x, y); 173 return SkColorSetA(0, addr[0]); 174 } 175 case kRGB_565_SkColorType: { 176 const uint16_t* addr = pixmap.addr16(x, y); 177 return SkPixel16ToColor(addr[0]); 178 } 179 case kARGB_4444_SkColorType: { 180 const uint16_t* addr = pixmap.addr16(x, y); 181 SkPMColor c = SkPixel4444ToPixel32(addr[0]); 182 return SkUnPreMultiply::PMColorToColor(c); 183 } 184 case kBGRA_8888_SkColorType: { 185 const uint32_t* addr = pixmap.addr32(x, y); 186 SkPMColor c = SkSwizzle_BGRA_to_PMColor(addr[0]); 187 return SkUnPreMultiply::PMColorToColor(c); 188 } 189 case kRGBA_8888_SkColorType: { 190 const uint32_t* addr = pixmap.addr32(x, y); 191 SkPMColor c = SkSwizzle_RGBA_to_PMColor(addr[0]); 192 return SkUnPreMultiply::PMColorToColor(c); 193 } 194 default: 195 return 0; 196 } 197 return 0; 198 } 199 200 SkRect TestUtils::getClipBounds(const SkCanvas* canvas) { 201 return SkRect::Make(canvas->getDeviceClipBounds()); 202 } 203 204 SkRect TestUtils::getLocalClipBounds(const SkCanvas* canvas) { 205 SkMatrix invertedTotalMatrix; 206 if (!canvas->getTotalMatrix().invert(&invertedTotalMatrix)) { 207 return SkRect::MakeEmpty(); 208 } 209 SkRect outlineInDeviceCoord = TestUtils::getClipBounds(canvas); 210 SkRect outlineInLocalCoord; 211 invertedTotalMatrix.mapRect(&outlineInLocalCoord, outlineInDeviceCoord); 212 return outlineInLocalCoord; 213 } 214 215 } /* namespace uirenderer */ 216 } /* namespace android */ 217