SkiaShader.cpp revision 06f96e2652e4855b6520ad9dd70583677605b79a
106f96e2652e4855b6520ad9dd70583677605b79aRomain Guy/*
206f96e2652e4855b6520ad9dd70583677605b79aRomain Guy * Copyright (C) 2010 The Android Open Source Project
306f96e2652e4855b6520ad9dd70583677605b79aRomain Guy *
406f96e2652e4855b6520ad9dd70583677605b79aRomain Guy * Licensed under the Apache License, Version 2.0 (the "License");
506f96e2652e4855b6520ad9dd70583677605b79aRomain Guy * you may not use this file except in compliance with the License.
606f96e2652e4855b6520ad9dd70583677605b79aRomain Guy * You may obtain a copy of the License at
706f96e2652e4855b6520ad9dd70583677605b79aRomain Guy *
806f96e2652e4855b6520ad9dd70583677605b79aRomain Guy *      http://www.apache.org/licenses/LICENSE-2.0
906f96e2652e4855b6520ad9dd70583677605b79aRomain Guy *
1006f96e2652e4855b6520ad9dd70583677605b79aRomain Guy * Unless required by applicable law or agreed to in writing, software
1106f96e2652e4855b6520ad9dd70583677605b79aRomain Guy * distributed under the License is distributed on an "AS IS" BASIS,
1206f96e2652e4855b6520ad9dd70583677605b79aRomain Guy * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1306f96e2652e4855b6520ad9dd70583677605b79aRomain Guy * See the License for the specific language governing permissions and
1406f96e2652e4855b6520ad9dd70583677605b79aRomain Guy * limitations under the License.
1506f96e2652e4855b6520ad9dd70583677605b79aRomain Guy */
1606f96e2652e4855b6520ad9dd70583677605b79aRomain Guy
1706f96e2652e4855b6520ad9dd70583677605b79aRomain Guy#define LOG_TAG "OpenGLRenderer"
1806f96e2652e4855b6520ad9dd70583677605b79aRomain Guy
1906f96e2652e4855b6520ad9dd70583677605b79aRomain Guy#include <utils/Log.h>
2006f96e2652e4855b6520ad9dd70583677605b79aRomain Guy
2106f96e2652e4855b6520ad9dd70583677605b79aRomain Guy#include <SkMatrix.h>
2206f96e2652e4855b6520ad9dd70583677605b79aRomain Guy
2306f96e2652e4855b6520ad9dd70583677605b79aRomain Guy#include "SkiaShader.h"
2406f96e2652e4855b6520ad9dd70583677605b79aRomain Guy#include "Texture.h"
2506f96e2652e4855b6520ad9dd70583677605b79aRomain Guy#include "Matrix.h"
2606f96e2652e4855b6520ad9dd70583677605b79aRomain Guy
2706f96e2652e4855b6520ad9dd70583677605b79aRomain Guynamespace android {
2806f96e2652e4855b6520ad9dd70583677605b79aRomain Guynamespace uirenderer {
2906f96e2652e4855b6520ad9dd70583677605b79aRomain Guy
3006f96e2652e4855b6520ad9dd70583677605b79aRomain Guy///////////////////////////////////////////////////////////////////////////////
3106f96e2652e4855b6520ad9dd70583677605b79aRomain Guy// Support
3206f96e2652e4855b6520ad9dd70583677605b79aRomain Guy///////////////////////////////////////////////////////////////////////////////
3306f96e2652e4855b6520ad9dd70583677605b79aRomain Guy
3406f96e2652e4855b6520ad9dd70583677605b79aRomain Guystatic const GLenum gTextureUnitsMap[] = {
3506f96e2652e4855b6520ad9dd70583677605b79aRomain Guy        GL_TEXTURE0,
3606f96e2652e4855b6520ad9dd70583677605b79aRomain Guy        GL_TEXTURE1,
3706f96e2652e4855b6520ad9dd70583677605b79aRomain Guy        GL_TEXTURE2
3806f96e2652e4855b6520ad9dd70583677605b79aRomain Guy};
3906f96e2652e4855b6520ad9dd70583677605b79aRomain Guy
4006f96e2652e4855b6520ad9dd70583677605b79aRomain Guystatic const GLint gTileModes[] = {
4106f96e2652e4855b6520ad9dd70583677605b79aRomain Guy        GL_CLAMP_TO_EDGE,   // == SkShader::kClamp_TileMode
4206f96e2652e4855b6520ad9dd70583677605b79aRomain Guy        GL_REPEAT,          // == SkShader::kRepeat_Mode
4306f96e2652e4855b6520ad9dd70583677605b79aRomain Guy        GL_MIRRORED_REPEAT  // == SkShader::kMirror_TileMode
4406f96e2652e4855b6520ad9dd70583677605b79aRomain Guy};
4506f96e2652e4855b6520ad9dd70583677605b79aRomain Guy
4606f96e2652e4855b6520ad9dd70583677605b79aRomain Guy///////////////////////////////////////////////////////////////////////////////
4706f96e2652e4855b6520ad9dd70583677605b79aRomain Guy// Base shader
4806f96e2652e4855b6520ad9dd70583677605b79aRomain Guy///////////////////////////////////////////////////////////////////////////////
4906f96e2652e4855b6520ad9dd70583677605b79aRomain Guy
5006f96e2652e4855b6520ad9dd70583677605b79aRomain GuySkiaShader::SkiaShader(Type type, SkShader* key, SkShader::TileMode tileX,
5106f96e2652e4855b6520ad9dd70583677605b79aRomain Guy        SkShader::TileMode tileY, SkMatrix* matrix, bool blend):
5206f96e2652e4855b6520ad9dd70583677605b79aRomain Guy        mType(type), mKey(key), mTileX(tileX), mTileY(tileY), mMatrix(matrix), mBlend(blend) {
5306f96e2652e4855b6520ad9dd70583677605b79aRomain Guy}
5406f96e2652e4855b6520ad9dd70583677605b79aRomain Guy
5506f96e2652e4855b6520ad9dd70583677605b79aRomain GuySkiaShader::~SkiaShader() {
5606f96e2652e4855b6520ad9dd70583677605b79aRomain Guy}
5706f96e2652e4855b6520ad9dd70583677605b79aRomain Guy
5806f96e2652e4855b6520ad9dd70583677605b79aRomain Guyvoid SkiaShader::describe(ProgramDescription& description, const Extensions& extensions) {
5906f96e2652e4855b6520ad9dd70583677605b79aRomain Guy}
6006f96e2652e4855b6520ad9dd70583677605b79aRomain Guy
6106f96e2652e4855b6520ad9dd70583677605b79aRomain Guyvoid SkiaShader::setupProgram(Program* program, const mat4& modelView, const Snapshot& snapshot,
6206f96e2652e4855b6520ad9dd70583677605b79aRomain Guy        GLuint* textureUnit) {
6306f96e2652e4855b6520ad9dd70583677605b79aRomain Guy}
6406f96e2652e4855b6520ad9dd70583677605b79aRomain Guy
6506f96e2652e4855b6520ad9dd70583677605b79aRomain Guyvoid SkiaShader::bindTexture(GLuint texture, GLenum wrapS, GLenum wrapT, GLuint textureUnit) {
6606f96e2652e4855b6520ad9dd70583677605b79aRomain Guy    glActiveTexture(gTextureUnitsMap[textureUnit]);
6706f96e2652e4855b6520ad9dd70583677605b79aRomain Guy    glBindTexture(GL_TEXTURE_2D, texture);
6806f96e2652e4855b6520ad9dd70583677605b79aRomain Guy    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrapS);
6906f96e2652e4855b6520ad9dd70583677605b79aRomain Guy    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrapT);
7006f96e2652e4855b6520ad9dd70583677605b79aRomain Guy}
7106f96e2652e4855b6520ad9dd70583677605b79aRomain Guy
7206f96e2652e4855b6520ad9dd70583677605b79aRomain Guy///////////////////////////////////////////////////////////////////////////////
7306f96e2652e4855b6520ad9dd70583677605b79aRomain Guy// Bitmap shader
7406f96e2652e4855b6520ad9dd70583677605b79aRomain Guy///////////////////////////////////////////////////////////////////////////////
7506f96e2652e4855b6520ad9dd70583677605b79aRomain Guy
7606f96e2652e4855b6520ad9dd70583677605b79aRomain GuySkiaBitmapShader::SkiaBitmapShader(SkBitmap* bitmap, SkShader* key, SkShader::TileMode tileX,
7706f96e2652e4855b6520ad9dd70583677605b79aRomain Guy        SkShader::TileMode tileY, SkMatrix* matrix, bool blend):
7806f96e2652e4855b6520ad9dd70583677605b79aRomain Guy        SkiaShader(kBitmap, key, tileX, tileY, matrix, blend), mBitmap(bitmap) {
7906f96e2652e4855b6520ad9dd70583677605b79aRomain Guy}
8006f96e2652e4855b6520ad9dd70583677605b79aRomain Guy
8106f96e2652e4855b6520ad9dd70583677605b79aRomain GuySkiaBitmapShader::~SkiaBitmapShader() {
8206f96e2652e4855b6520ad9dd70583677605b79aRomain Guy}
8306f96e2652e4855b6520ad9dd70583677605b79aRomain Guy
8406f96e2652e4855b6520ad9dd70583677605b79aRomain Guyvoid SkiaBitmapShader::describe(ProgramDescription& description, const Extensions& extensions) {
8506f96e2652e4855b6520ad9dd70583677605b79aRomain Guy    const Texture* texture = mTextureCache->get(mBitmap);
8606f96e2652e4855b6520ad9dd70583677605b79aRomain Guy
8706f96e2652e4855b6520ad9dd70583677605b79aRomain Guy    const float width = texture->width;
8806f96e2652e4855b6520ad9dd70583677605b79aRomain Guy    const float height = texture->height;
8906f96e2652e4855b6520ad9dd70583677605b79aRomain Guy
9006f96e2652e4855b6520ad9dd70583677605b79aRomain Guy    description.hasBitmap = true;
9106f96e2652e4855b6520ad9dd70583677605b79aRomain Guy    // The driver does not support non-power of two mirrored/repeated
9206f96e2652e4855b6520ad9dd70583677605b79aRomain Guy    // textures, so do it ourselves
9306f96e2652e4855b6520ad9dd70583677605b79aRomain Guy    if (!extensions.hasNPot() && !isPowerOfTwo(width) && !isPowerOfTwo(height)) {
9406f96e2652e4855b6520ad9dd70583677605b79aRomain Guy        description.isBitmapNpot = true;
9506f96e2652e4855b6520ad9dd70583677605b79aRomain Guy        description.bitmapWrapS = gTileModes[mTileX];
9606f96e2652e4855b6520ad9dd70583677605b79aRomain Guy        description.bitmapWrapT = gTileModes[mTileY];
9706f96e2652e4855b6520ad9dd70583677605b79aRomain Guy    }
9806f96e2652e4855b6520ad9dd70583677605b79aRomain Guy}
9906f96e2652e4855b6520ad9dd70583677605b79aRomain Guy
10006f96e2652e4855b6520ad9dd70583677605b79aRomain Guyvoid SkiaBitmapShader::setupProgram(Program* program, const mat4& modelView,
10106f96e2652e4855b6520ad9dd70583677605b79aRomain Guy        const Snapshot& snapshot, GLuint* textureUnit) {
10206f96e2652e4855b6520ad9dd70583677605b79aRomain Guy    GLuint textureSlot = (*textureUnit)++;
10306f96e2652e4855b6520ad9dd70583677605b79aRomain Guy    glActiveTexture(gTextureUnitsMap[textureSlot]);
10406f96e2652e4855b6520ad9dd70583677605b79aRomain Guy    const Texture* texture = mTextureCache->get(mBitmap);
10506f96e2652e4855b6520ad9dd70583677605b79aRomain Guy
10606f96e2652e4855b6520ad9dd70583677605b79aRomain Guy    const float width = texture->width;
10706f96e2652e4855b6520ad9dd70583677605b79aRomain Guy    const float height = texture->height;
10806f96e2652e4855b6520ad9dd70583677605b79aRomain Guy
10906f96e2652e4855b6520ad9dd70583677605b79aRomain Guy    mat4 textureTransform;
11006f96e2652e4855b6520ad9dd70583677605b79aRomain Guy    if (mMatrix) {
11106f96e2652e4855b6520ad9dd70583677605b79aRomain Guy        SkMatrix inverse;
11206f96e2652e4855b6520ad9dd70583677605b79aRomain Guy        mMatrix->invert(&inverse);
11306f96e2652e4855b6520ad9dd70583677605b79aRomain Guy        textureTransform.load(inverse);
11406f96e2652e4855b6520ad9dd70583677605b79aRomain Guy        textureTransform.multiply(modelView);
11506f96e2652e4855b6520ad9dd70583677605b79aRomain Guy    } else {
11606f96e2652e4855b6520ad9dd70583677605b79aRomain Guy        textureTransform.load(modelView);
11706f96e2652e4855b6520ad9dd70583677605b79aRomain Guy    }
11806f96e2652e4855b6520ad9dd70583677605b79aRomain Guy
11906f96e2652e4855b6520ad9dd70583677605b79aRomain Guy    // Uniforms
12006f96e2652e4855b6520ad9dd70583677605b79aRomain Guy    bindTexture(texture->id, gTileModes[mTileX], gTileModes[mTileY], textureSlot);
12106f96e2652e4855b6520ad9dd70583677605b79aRomain Guy    glUniform1i(program->getUniform("bitmapSampler"), textureSlot);
12206f96e2652e4855b6520ad9dd70583677605b79aRomain Guy    glUniformMatrix4fv(program->getUniform("textureTransform"), 1,
12306f96e2652e4855b6520ad9dd70583677605b79aRomain Guy            GL_FALSE, &textureTransform.data[0]);
12406f96e2652e4855b6520ad9dd70583677605b79aRomain Guy    glUniform2f(program->getUniform("textureDimension"), 1.0f / width, 1.0f / height);
12506f96e2652e4855b6520ad9dd70583677605b79aRomain Guy}
12606f96e2652e4855b6520ad9dd70583677605b79aRomain Guy
12706f96e2652e4855b6520ad9dd70583677605b79aRomain Guy///////////////////////////////////////////////////////////////////////////////
12806f96e2652e4855b6520ad9dd70583677605b79aRomain Guy// Linear gradient shader
12906f96e2652e4855b6520ad9dd70583677605b79aRomain Guy///////////////////////////////////////////////////////////////////////////////
13006f96e2652e4855b6520ad9dd70583677605b79aRomain Guy
13106f96e2652e4855b6520ad9dd70583677605b79aRomain GuySkiaLinearGradientShader::SkiaLinearGradientShader(float* bounds, uint32_t* colors,
13206f96e2652e4855b6520ad9dd70583677605b79aRomain Guy        float* positions, int count, SkShader* key, SkShader::TileMode tileMode,
13306f96e2652e4855b6520ad9dd70583677605b79aRomain Guy        SkMatrix* matrix, bool blend):
13406f96e2652e4855b6520ad9dd70583677605b79aRomain Guy        SkiaShader(kLinearGradient, key, tileMode, tileMode, matrix, blend),
13506f96e2652e4855b6520ad9dd70583677605b79aRomain Guy        mBounds(bounds), mColors(colors), mPositions(positions), mCount(count) {
13606f96e2652e4855b6520ad9dd70583677605b79aRomain Guy}
13706f96e2652e4855b6520ad9dd70583677605b79aRomain Guy
13806f96e2652e4855b6520ad9dd70583677605b79aRomain GuySkiaLinearGradientShader::~SkiaLinearGradientShader() {
13906f96e2652e4855b6520ad9dd70583677605b79aRomain Guy    delete mBounds;
14006f96e2652e4855b6520ad9dd70583677605b79aRomain Guy    delete mColors;
14106f96e2652e4855b6520ad9dd70583677605b79aRomain Guy    delete mPositions;
14206f96e2652e4855b6520ad9dd70583677605b79aRomain Guy}
14306f96e2652e4855b6520ad9dd70583677605b79aRomain Guy
14406f96e2652e4855b6520ad9dd70583677605b79aRomain Guyvoid SkiaLinearGradientShader::describe(ProgramDescription& description,
14506f96e2652e4855b6520ad9dd70583677605b79aRomain Guy        const Extensions& extensions) {
14606f96e2652e4855b6520ad9dd70583677605b79aRomain Guy    description.hasGradient = true;
14706f96e2652e4855b6520ad9dd70583677605b79aRomain Guy}
14806f96e2652e4855b6520ad9dd70583677605b79aRomain Guy
14906f96e2652e4855b6520ad9dd70583677605b79aRomain Guyvoid SkiaLinearGradientShader::setupProgram(Program* program, const mat4& modelView,
15006f96e2652e4855b6520ad9dd70583677605b79aRomain Guy        const Snapshot& snapshot, GLuint* textureUnit) {
15106f96e2652e4855b6520ad9dd70583677605b79aRomain Guy    GLuint textureSlot = (*textureUnit)++;
15206f96e2652e4855b6520ad9dd70583677605b79aRomain Guy    glActiveTexture(gTextureUnitsMap[textureSlot]);
15306f96e2652e4855b6520ad9dd70583677605b79aRomain Guy
15406f96e2652e4855b6520ad9dd70583677605b79aRomain Guy    Texture* texture = mGradientCache->get(mKey);
15506f96e2652e4855b6520ad9dd70583677605b79aRomain Guy    if (!texture) {
15606f96e2652e4855b6520ad9dd70583677605b79aRomain Guy        texture = mGradientCache->addLinearGradient(mKey, mBounds, mColors, mPositions,
15706f96e2652e4855b6520ad9dd70583677605b79aRomain Guy                mCount, mTileX);
15806f96e2652e4855b6520ad9dd70583677605b79aRomain Guy    }
15906f96e2652e4855b6520ad9dd70583677605b79aRomain Guy
16006f96e2652e4855b6520ad9dd70583677605b79aRomain Guy    Rect start(mBounds[0], mBounds[1], mBounds[2], mBounds[3]);
16106f96e2652e4855b6520ad9dd70583677605b79aRomain Guy    if (mMatrix) {
16206f96e2652e4855b6520ad9dd70583677605b79aRomain Guy        mat4 shaderMatrix(*mMatrix);
16306f96e2652e4855b6520ad9dd70583677605b79aRomain Guy        shaderMatrix.mapRect(start);
16406f96e2652e4855b6520ad9dd70583677605b79aRomain Guy    }
16506f96e2652e4855b6520ad9dd70583677605b79aRomain Guy    snapshot.transform.mapRect(start);
16606f96e2652e4855b6520ad9dd70583677605b79aRomain Guy
16706f96e2652e4855b6520ad9dd70583677605b79aRomain Guy    const float gradientX = start.right - start.left;
16806f96e2652e4855b6520ad9dd70583677605b79aRomain Guy    const float gradientY = start.bottom - start.top;
16906f96e2652e4855b6520ad9dd70583677605b79aRomain Guy
17006f96e2652e4855b6520ad9dd70583677605b79aRomain Guy    mat4 screenSpace(snapshot.transform);
17106f96e2652e4855b6520ad9dd70583677605b79aRomain Guy    screenSpace.multiply(modelView);
17206f96e2652e4855b6520ad9dd70583677605b79aRomain Guy
17306f96e2652e4855b6520ad9dd70583677605b79aRomain Guy    // Uniforms
17406f96e2652e4855b6520ad9dd70583677605b79aRomain Guy    bindTexture(texture->id, gTileModes[mTileX], gTileModes[mTileY], textureSlot);
17506f96e2652e4855b6520ad9dd70583677605b79aRomain Guy    glUniform1i(program->getUniform("gradientSampler"), textureSlot);
17606f96e2652e4855b6520ad9dd70583677605b79aRomain Guy    glUniform2f(program->getUniform("gradientStart"), start.left, start.top);
17706f96e2652e4855b6520ad9dd70583677605b79aRomain Guy    glUniform2f(program->getUniform("gradient"), gradientX, gradientY);
17806f96e2652e4855b6520ad9dd70583677605b79aRomain Guy    glUniform1f(program->getUniform("gradientLength"),
17906f96e2652e4855b6520ad9dd70583677605b79aRomain Guy            1.0f / (gradientX * gradientX + gradientY * gradientY));
18006f96e2652e4855b6520ad9dd70583677605b79aRomain Guy    glUniformMatrix4fv(program->getUniform("screenSpace"), 1, GL_FALSE, &screenSpace.data[0]);
18106f96e2652e4855b6520ad9dd70583677605b79aRomain Guy}
18206f96e2652e4855b6520ad9dd70583677605b79aRomain Guy
18306f96e2652e4855b6520ad9dd70583677605b79aRomain Guy///////////////////////////////////////////////////////////////////////////////
18406f96e2652e4855b6520ad9dd70583677605b79aRomain Guy// Compose shader
18506f96e2652e4855b6520ad9dd70583677605b79aRomain Guy///////////////////////////////////////////////////////////////////////////////
18606f96e2652e4855b6520ad9dd70583677605b79aRomain Guy
18706f96e2652e4855b6520ad9dd70583677605b79aRomain GuySkiaComposeShader::SkiaComposeShader(SkiaShader* first, SkiaShader* second,
18806f96e2652e4855b6520ad9dd70583677605b79aRomain Guy        SkXfermode::Mode mode, SkShader* key):
18906f96e2652e4855b6520ad9dd70583677605b79aRomain Guy        SkiaShader(kCompose, key, SkShader::kClamp_TileMode, SkShader::kClamp_TileMode,
19006f96e2652e4855b6520ad9dd70583677605b79aRomain Guy        NULL, first->blend() || second->blend()), mFirst(first), mSecond(second), mMode(mode) {
19106f96e2652e4855b6520ad9dd70583677605b79aRomain Guy}
19206f96e2652e4855b6520ad9dd70583677605b79aRomain Guy
19306f96e2652e4855b6520ad9dd70583677605b79aRomain GuySkiaComposeShader::~SkiaComposeShader() {
19406f96e2652e4855b6520ad9dd70583677605b79aRomain Guy    delete mFirst;
19506f96e2652e4855b6520ad9dd70583677605b79aRomain Guy    delete mSecond;
19606f96e2652e4855b6520ad9dd70583677605b79aRomain Guy}
19706f96e2652e4855b6520ad9dd70583677605b79aRomain Guy
19806f96e2652e4855b6520ad9dd70583677605b79aRomain Guyvoid SkiaComposeShader::set(TextureCache* textureCache, GradientCache* gradientCache) {
19906f96e2652e4855b6520ad9dd70583677605b79aRomain Guy    SkiaShader::set(textureCache, gradientCache);
20006f96e2652e4855b6520ad9dd70583677605b79aRomain Guy    mFirst->set(textureCache, gradientCache);
20106f96e2652e4855b6520ad9dd70583677605b79aRomain Guy    mSecond->set(textureCache, gradientCache);
20206f96e2652e4855b6520ad9dd70583677605b79aRomain Guy}
20306f96e2652e4855b6520ad9dd70583677605b79aRomain Guy
20406f96e2652e4855b6520ad9dd70583677605b79aRomain Guyvoid SkiaComposeShader::describe(ProgramDescription& description, const Extensions& extensions) {
20506f96e2652e4855b6520ad9dd70583677605b79aRomain Guy    mFirst->describe(description, extensions);
20606f96e2652e4855b6520ad9dd70583677605b79aRomain Guy    mSecond->describe(description, extensions);
20706f96e2652e4855b6520ad9dd70583677605b79aRomain Guy    if (mFirst->type() == kBitmap) {
20806f96e2652e4855b6520ad9dd70583677605b79aRomain Guy        description.isBitmapFirst = true;
20906f96e2652e4855b6520ad9dd70583677605b79aRomain Guy    }
21006f96e2652e4855b6520ad9dd70583677605b79aRomain Guy    description.shadersMode = mMode;
21106f96e2652e4855b6520ad9dd70583677605b79aRomain Guy}
21206f96e2652e4855b6520ad9dd70583677605b79aRomain Guy
21306f96e2652e4855b6520ad9dd70583677605b79aRomain Guyvoid SkiaComposeShader::setupProgram(Program* program, const mat4& modelView,
21406f96e2652e4855b6520ad9dd70583677605b79aRomain Guy        const Snapshot& snapshot, GLuint* textureUnit) {
21506f96e2652e4855b6520ad9dd70583677605b79aRomain Guy    mFirst->setupProgram(program, modelView, snapshot, textureUnit);
21606f96e2652e4855b6520ad9dd70583677605b79aRomain Guy    mSecond->setupProgram(program, modelView, snapshot, textureUnit);
21706f96e2652e4855b6520ad9dd70583677605b79aRomain Guy}
21806f96e2652e4855b6520ad9dd70583677605b79aRomain Guy
21906f96e2652e4855b6520ad9dd70583677605b79aRomain Guy}; // namespace uirenderer
22006f96e2652e4855b6520ad9dd70583677605b79aRomain Guy}; // namespace android
221