OpenGLRenderer.cpp revision b45c0c9774bd19a9dbe77d149abae4e124b08bf6
1/*
2 * Copyright (C) 2010 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#define LOG_TAG "OpenGLRenderer"
18
19#include <stdlib.h>
20#include <stdint.h>
21#include <sys/types.h>
22
23#include <SkCanvas.h>
24#include <SkTypeface.h>
25
26#include <utils/Log.h>
27
28#include "OpenGLRenderer.h"
29
30namespace android {
31namespace uirenderer {
32
33///////////////////////////////////////////////////////////////////////////////
34// Defines
35///////////////////////////////////////////////////////////////////////////////
36
37#define REQUIRED_TEXTURE_UNITS_COUNT 3
38
39// Generates simple and textured vertices
40#define FV(x, y, u, v) { { x, y }, { u, v } }
41
42///////////////////////////////////////////////////////////////////////////////
43// Globals
44///////////////////////////////////////////////////////////////////////////////
45
46// This array is never used directly but used as a memcpy source in the
47// OpenGLRenderer constructor
48static const TextureVertex gMeshVertices[] = {
49        FV(0.0f, 0.0f, 0.0f, 0.0f),
50        FV(1.0f, 0.0f, 1.0f, 0.0f),
51        FV(0.0f, 1.0f, 0.0f, 1.0f),
52        FV(1.0f, 1.0f, 1.0f, 1.0f)
53};
54static const GLsizei gMeshStride = sizeof(TextureVertex);
55static const GLsizei gMeshCount = 4;
56
57/**
58 * Structure mapping Skia xfermodes to OpenGL blending factors.
59 */
60struct Blender {
61    SkXfermode::Mode mode;
62    GLenum src;
63    GLenum dst;
64}; // struct Blender
65
66// In this array, the index of each Blender equals the value of the first
67// entry. For instance, gBlends[1] == gBlends[SkXfermode::kSrc_Mode]
68static const Blender gBlends[] = {
69        { SkXfermode::kClear_Mode,   GL_ZERO,                 GL_ZERO },
70        { SkXfermode::kSrc_Mode,     GL_ONE,                  GL_ZERO },
71        { SkXfermode::kDst_Mode,     GL_ZERO,                 GL_ONE },
72        { SkXfermode::kSrcOver_Mode, GL_ONE,                  GL_ONE_MINUS_SRC_ALPHA },
73        { SkXfermode::kDstOver_Mode, GL_ONE_MINUS_DST_ALPHA,  GL_ONE },
74        { SkXfermode::kSrcIn_Mode,   GL_DST_ALPHA,            GL_ZERO },
75        { SkXfermode::kDstIn_Mode,   GL_ZERO,                 GL_SRC_ALPHA },
76        { SkXfermode::kSrcOut_Mode,  GL_ONE_MINUS_DST_ALPHA,  GL_ZERO },
77        { SkXfermode::kDstOut_Mode,  GL_ZERO,                 GL_ONE_MINUS_SRC_ALPHA },
78        { SkXfermode::kSrcATop_Mode, GL_DST_ALPHA,            GL_ONE_MINUS_SRC_ALPHA },
79        { SkXfermode::kDstATop_Mode, GL_ONE_MINUS_DST_ALPHA,  GL_SRC_ALPHA },
80        { SkXfermode::kXor_Mode,     GL_ONE_MINUS_DST_ALPHA,  GL_ONE_MINUS_SRC_ALPHA }
81};
82
83static const GLenum gTextureUnits[] = {
84        GL_TEXTURE0,
85        GL_TEXTURE1,
86        GL_TEXTURE2
87};
88
89///////////////////////////////////////////////////////////////////////////////
90// Constructors/destructor
91///////////////////////////////////////////////////////////////////////////////
92
93OpenGLRenderer::OpenGLRenderer(): mCaches(Caches::getInstance()) {
94    LOGD("Create OpenGLRenderer");
95
96    mShader = NULL;
97    mColorFilter = NULL;
98    mHasShadow = false;
99
100    memcpy(mMeshVertices, gMeshVertices, sizeof(gMeshVertices));
101
102    mFirstSnapshot = new Snapshot;
103
104    GLint maxTextureUnits;
105    glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &maxTextureUnits);
106    if (maxTextureUnits < REQUIRED_TEXTURE_UNITS_COUNT) {
107        LOGW("At least %d texture units are required!", REQUIRED_TEXTURE_UNITS_COUNT);
108    }
109}
110
111OpenGLRenderer::~OpenGLRenderer() {
112    LOGD("Destroy OpenGLRenderer");
113}
114
115///////////////////////////////////////////////////////////////////////////////
116// Setup
117///////////////////////////////////////////////////////////////////////////////
118
119void OpenGLRenderer::setViewport(int width, int height) {
120    glViewport(0, 0, width, height);
121    mOrthoMatrix.loadOrtho(0, width, height, 0, -1, 1);
122
123    mWidth = width;
124    mHeight = height;
125    mFirstSnapshot->height = height;
126    mFirstSnapshot->viewport.set(0, 0, width, height);
127}
128
129void OpenGLRenderer::prepare() {
130    mSnapshot = new Snapshot(mFirstSnapshot);
131    mSaveCount = 1;
132
133    glViewport(0, 0, mWidth, mHeight);
134
135    glDisable(GL_SCISSOR_TEST);
136
137    glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
138    glClear(GL_COLOR_BUFFER_BIT);
139
140    glEnable(GL_SCISSOR_TEST);
141    glScissor(0, 0, mWidth, mHeight);
142
143    mSnapshot->setClip(0.0f, 0.0f, mWidth, mHeight);
144}
145
146///////////////////////////////////////////////////////////////////////////////
147// State management
148///////////////////////////////////////////////////////////////////////////////
149
150int OpenGLRenderer::getSaveCount() const {
151    return mSaveCount;
152}
153
154int OpenGLRenderer::save(int flags) {
155    return saveSnapshot();
156}
157
158void OpenGLRenderer::restore() {
159    if (mSaveCount > 1) {
160        restoreSnapshot();
161    }
162}
163
164void OpenGLRenderer::restoreToCount(int saveCount) {
165    if (saveCount < 1) saveCount = 1;
166
167    while (mSaveCount > saveCount) {
168        restoreSnapshot();
169    }
170}
171
172int OpenGLRenderer::saveSnapshot() {
173    mSnapshot = new Snapshot(mSnapshot);
174    return mSaveCount++;
175}
176
177bool OpenGLRenderer::restoreSnapshot() {
178    bool restoreClip = mSnapshot->flags & Snapshot::kFlagClipSet;
179    bool restoreLayer = mSnapshot->flags & Snapshot::kFlagIsLayer;
180    bool restoreOrtho = mSnapshot->flags & Snapshot::kFlagDirtyOrtho;
181
182    sp<Snapshot> current = mSnapshot;
183    sp<Snapshot> previous = mSnapshot->previous;
184
185    if (restoreOrtho) {
186        Rect& r = previous->viewport;
187        glViewport(r.left, r.top, r.right, r.bottom);
188        mOrthoMatrix.load(current->orthoMatrix);
189    }
190
191    mSaveCount--;
192    mSnapshot = previous;
193
194    if (restoreLayer) {
195        composeLayer(current, previous);
196    }
197
198    if (restoreClip) {
199        setScissorFromClip();
200    }
201
202    return restoreClip;
203}
204
205///////////////////////////////////////////////////////////////////////////////
206// Layers
207///////////////////////////////////////////////////////////////////////////////
208
209int OpenGLRenderer::saveLayer(float left, float top, float right, float bottom,
210        const SkPaint* p, int flags) {
211    int count = saveSnapshot();
212
213    int alpha = 255;
214    SkXfermode::Mode mode;
215
216    if (p) {
217        alpha = p->getAlpha();
218        const bool isMode = SkXfermode::IsMode(p->getXfermode(), &mode);
219        if (!isMode) {
220            // Assume SRC_OVER
221            mode = SkXfermode::kSrcOver_Mode;
222        }
223    } else {
224        mode = SkXfermode::kSrcOver_Mode;
225    }
226
227    if (alpha > 0 && !mSnapshot->invisible) {
228        createLayer(mSnapshot, left, top, right, bottom, alpha, mode, flags);
229    } else {
230        mSnapshot->invisible = true;
231    }
232
233    return count;
234}
235
236int OpenGLRenderer::saveLayerAlpha(float left, float top, float right, float bottom,
237        int alpha, int flags) {
238    int count = saveSnapshot();
239    if (alpha > 0 && !mSnapshot->invisible) {
240        createLayer(mSnapshot, left, top, right, bottom, alpha, SkXfermode::kSrcOver_Mode, flags);
241    } else {
242        mSnapshot->invisible = true;
243    }
244    return count;
245}
246
247bool OpenGLRenderer::createLayer(sp<Snapshot> snapshot, float left, float top,
248        float right, float bottom, int alpha, SkXfermode::Mode mode,int flags) {
249    LAYER_LOGD("Requesting layer %fx%f", right - left, bottom - top);
250    LAYER_LOGD("Layer cache size = %d", mCaches.layerCache.getSize());
251
252    GLuint previousFbo = snapshot->previous.get() ? snapshot->previous->fbo : 0;
253    LayerSize size(right - left, bottom - top);
254
255    Layer* layer = mCaches.layerCache.get(size, previousFbo);
256    if (!layer) {
257        return false;
258    }
259
260    glBindFramebuffer(GL_FRAMEBUFFER, layer->fbo);
261
262    // Clear the FBO
263    glDisable(GL_SCISSOR_TEST);
264    glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
265    glClear(GL_COLOR_BUFFER_BIT);
266    glEnable(GL_SCISSOR_TEST);
267
268    layer->mode = mode;
269    layer->alpha = alpha / 255.0f;
270    layer->layer.set(left, top, right, bottom);
271
272    // Save the layer in the snapshot
273    snapshot->flags |= Snapshot::kFlagIsLayer;
274    snapshot->layer = layer;
275    snapshot->fbo = layer->fbo;
276    snapshot->transform.loadTranslate(-left, -top, 0.0f);
277    snapshot->setClip(0.0f, 0.0f, right - left, bottom - top);
278    snapshot->viewport.set(0.0f, 0.0f, right - left, bottom - top);
279    snapshot->height = bottom - top;
280    snapshot->flags |= Snapshot::kFlagDirtyOrtho;
281    snapshot->orthoMatrix.load(mOrthoMatrix);
282
283    setScissorFromClip();
284
285    // Change the ortho projection
286    glViewport(0, 0, right - left, bottom - top);
287    mOrthoMatrix.loadOrtho(0.0f, right - left, bottom - top, 0.0f, -1.0f, 1.0f);
288
289    return true;
290}
291
292void OpenGLRenderer::composeLayer(sp<Snapshot> current, sp<Snapshot> previous) {
293    if (!current->layer) {
294        LOGE("Attempting to compose a layer that does not exist");
295        return;
296    }
297
298    // Unbind current FBO and restore previous one
299    // Most of the time, previous->fbo will be 0 to bind the default buffer
300    glBindFramebuffer(GL_FRAMEBUFFER, previous->fbo);
301
302    // Restore the clip from the previous snapshot
303    const Rect& clip = previous->clipRect;
304    glScissor(clip.left, mHeight - clip.bottom, clip.getWidth(), clip.getHeight());
305
306    Layer* layer = current->layer;
307    const Rect& rect = layer->layer;
308
309    // FBOs are already drawn with a top-left origin, don't flip the texture
310    resetDrawTextureTexCoords(0.0f, 1.0f, 1.0f, 0.0f);
311
312    drawTextureRect(rect.left, rect.top, rect.right, rect.bottom,
313            layer->texture, layer->alpha, layer->mode, layer->blend);
314
315    resetDrawTextureTexCoords(0.0f, 0.0f, 1.0f, 1.0f);
316
317    LayerSize size(rect.getWidth(), rect.getHeight());
318    // Failing to add the layer to the cache should happen only if the
319    // layer is too large
320    if (!mCaches.layerCache.put(size, layer)) {
321        LAYER_LOGD("Deleting layer");
322
323        glDeleteFramebuffers(1, &layer->fbo);
324        glDeleteTextures(1, &layer->texture);
325
326        delete layer;
327    }
328}
329
330///////////////////////////////////////////////////////////////////////////////
331// Transforms
332///////////////////////////////////////////////////////////////////////////////
333
334void OpenGLRenderer::translate(float dx, float dy) {
335    mSnapshot->transform.translate(dx, dy, 0.0f);
336}
337
338void OpenGLRenderer::rotate(float degrees) {
339    mSnapshot->transform.rotate(degrees, 0.0f, 0.0f, 1.0f);
340}
341
342void OpenGLRenderer::scale(float sx, float sy) {
343    mSnapshot->transform.scale(sx, sy, 1.0f);
344}
345
346void OpenGLRenderer::setMatrix(SkMatrix* matrix) {
347    mSnapshot->transform.load(*matrix);
348}
349
350void OpenGLRenderer::getMatrix(SkMatrix* matrix) {
351    mSnapshot->transform.copyTo(*matrix);
352}
353
354void OpenGLRenderer::concatMatrix(SkMatrix* matrix) {
355    mat4 m(*matrix);
356    mSnapshot->transform.multiply(m);
357}
358
359///////////////////////////////////////////////////////////////////////////////
360// Clipping
361///////////////////////////////////////////////////////////////////////////////
362
363void OpenGLRenderer::setScissorFromClip() {
364    const Rect& clip = mSnapshot->clipRect;
365    glScissor(clip.left, mSnapshot->height - clip.bottom, clip.getWidth(), clip.getHeight());
366}
367
368const Rect& OpenGLRenderer::getClipBounds() {
369    return mSnapshot->getLocalClip();
370}
371
372bool OpenGLRenderer::quickReject(float left, float top, float right, float bottom) {
373    if (mSnapshot->invisible) return true;
374
375    Rect r(left, top, right, bottom);
376    mSnapshot->transform.mapRect(r);
377    return !mSnapshot->clipRect.intersects(r);
378}
379
380bool OpenGLRenderer::clipRect(float left, float top, float right, float bottom, SkRegion::Op op) {
381    bool clipped = mSnapshot->clip(left, top, right, bottom, op);
382    if (clipped) {
383        setScissorFromClip();
384    }
385    return !mSnapshot->clipRect.isEmpty();
386}
387
388///////////////////////////////////////////////////////////////////////////////
389// Drawing
390///////////////////////////////////////////////////////////////////////////////
391
392void OpenGLRenderer::drawBitmap(SkBitmap* bitmap, float left, float top, const SkPaint* paint) {
393    const float right = left + bitmap->width();
394    const float bottom = top + bitmap->height();
395
396    if (quickReject(left, top, right, bottom)) {
397        return;
398    }
399
400    glActiveTexture(GL_TEXTURE0);
401    const Texture* texture = mCaches.textureCache.get(bitmap);
402    if (!texture) return;
403    const AutoTexture autoCleanup(texture);
404
405    drawTextureRect(left, top, right, bottom, texture, paint);
406}
407
408void OpenGLRenderer::drawBitmap(SkBitmap* bitmap, const SkMatrix* matrix, const SkPaint* paint) {
409    Rect r(0.0f, 0.0f, bitmap->width(), bitmap->height());
410    const mat4 transform(*matrix);
411    transform.mapRect(r);
412
413    if (quickReject(r.left, r.top, r.right, r.bottom)) {
414        return;
415    }
416
417    glActiveTexture(GL_TEXTURE0);
418    const Texture* texture = mCaches.textureCache.get(bitmap);
419    if (!texture) return;
420    const AutoTexture autoCleanup(texture);
421
422    drawTextureRect(r.left, r.top, r.right, r.bottom, texture, paint);
423}
424
425void OpenGLRenderer::drawBitmap(SkBitmap* bitmap,
426         float srcLeft, float srcTop, float srcRight, float srcBottom,
427         float dstLeft, float dstTop, float dstRight, float dstBottom,
428         const SkPaint* paint) {
429    if (quickReject(dstLeft, dstTop, dstRight, dstBottom)) {
430        return;
431    }
432
433    glActiveTexture(GL_TEXTURE0);
434    const Texture* texture = mCaches.textureCache.get(bitmap);
435    if (!texture) return;
436    const AutoTexture autoCleanup(texture);
437
438    const float width = texture->width;
439    const float height = texture->height;
440
441    const float u1 = srcLeft / width;
442    const float v1 = srcTop / height;
443    const float u2 = srcRight / width;
444    const float v2 = srcBottom / height;
445
446    resetDrawTextureTexCoords(u1, v1, u2, v2);
447
448    drawTextureRect(dstLeft, dstTop, dstRight, dstBottom, texture, paint);
449
450    resetDrawTextureTexCoords(0.0f, 0.0f, 1.0f, 1.0f);
451}
452
453void OpenGLRenderer::drawPatch(SkBitmap* bitmap, Res_png_9patch* patch,
454        float left, float top, float right, float bottom, const SkPaint* paint) {
455    if (quickReject(left, top, right, bottom)) {
456        return;
457    }
458
459    glActiveTexture(GL_TEXTURE0);
460    const Texture* texture = mCaches.textureCache.get(bitmap);
461    if (!texture) return;
462    const AutoTexture autoCleanup(texture);
463
464    int alpha;
465    SkXfermode::Mode mode;
466    getAlphaAndMode(paint, &alpha, &mode);
467
468    Patch* mesh = mCaches.patchCache.get(patch);
469    mesh->updateVertices(bitmap, left, top, right, bottom,
470            &patch->xDivs[0], &patch->yDivs[0], patch->numXDivs, patch->numYDivs);
471
472    // Specify right and bottom as +1.0f from left/top to prevent scaling since the
473    // patch mesh already defines the final size
474    drawTextureMesh(left, top, left + 1.0f, top + 1.0f, texture->id, alpha / 255.0f,
475            mode, texture->blend, &mesh->vertices[0].position[0],
476            &mesh->vertices[0].texture[0], mesh->indices, mesh->indicesCount);
477}
478
479void OpenGLRenderer::drawColor(int color, SkXfermode::Mode mode) {
480    if (mSnapshot->invisible) return;
481    const Rect& clip = mSnapshot->clipRect;
482    drawColorRect(clip.left, clip.top, clip.right, clip.bottom, color, mode, true);
483}
484
485void OpenGLRenderer::drawRect(float left, float top, float right, float bottom, const SkPaint* p) {
486    if (quickReject(left, top, right, bottom)) {
487        return;
488    }
489
490    SkXfermode::Mode mode;
491
492    const bool isMode = SkXfermode::IsMode(p->getXfermode(), &mode);
493    if (!isMode) {
494        // Assume SRC_OVER
495        mode = SkXfermode::kSrcOver_Mode;
496    }
497
498    // Skia draws using the color's alpha channel if < 255
499    // Otherwise, it uses the paint's alpha
500    int color = p->getColor();
501    if (((color >> 24) & 0xff) == 255) {
502        color |= p->getAlpha() << 24;
503    }
504
505    drawColorRect(left, top, right, bottom, color, mode);
506}
507
508void OpenGLRenderer::drawText(const char* text, int bytesCount, int count,
509        float x, float y, SkPaint* paint) {
510    if (mSnapshot->invisible || text == NULL || count == 0 ||
511            (paint->getAlpha() == 0 && paint->getXfermode() == NULL)) {
512        return;
513    }
514
515    float scaleX = paint->getTextScaleX();
516    bool applyScaleX = scaleX < 0.9999f || scaleX > 1.0001f;
517    if (applyScaleX) {
518        save(0);
519        translate(x - (x * scaleX), 0.0f);
520        scale(scaleX, 1.0f);
521    }
522
523    float length = -1.0f;
524    switch (paint->getTextAlign()) {
525        case SkPaint::kCenter_Align:
526            length = paint->measureText(text, bytesCount);
527            x -= length / 2.0f;
528            break;
529        case SkPaint::kRight_Align:
530            length = paint->measureText(text, bytesCount);
531            x -= length;
532            break;
533        default:
534            break;
535    }
536
537    int alpha;
538    SkXfermode::Mode mode;
539    getAlphaAndMode(paint, &alpha, &mode);
540
541    uint32_t color = paint->getColor();
542    const GLfloat a = alpha / 255.0f;
543    const GLfloat r = a * ((color >> 16) & 0xFF) / 255.0f;
544    const GLfloat g = a * ((color >>  8) & 0xFF) / 255.0f;
545    const GLfloat b = a * ((color      ) & 0xFF) / 255.0f;
546
547    FontRenderer& fontRenderer = mCaches.fontRenderer.getFontRenderer(paint);
548    fontRenderer.setFont(paint, SkTypeface::UniqueID(paint->getTypeface()),
549            paint->getTextSize());
550    if (mHasShadow) {
551        glActiveTexture(gTextureUnits[0]);
552        mCaches.dropShadowCache.setFontRenderer(fontRenderer);
553        const ShadowTexture* shadow = mCaches.dropShadowCache.get(paint, text, bytesCount,
554                count, mShadowRadius);
555        const AutoTexture autoCleanup(shadow);
556
557        setupShadow(shadow, x, y, mode, a);
558
559        // Draw the mesh
560        glDrawArrays(GL_TRIANGLE_STRIP, 0, gMeshCount);
561        glDisableVertexAttribArray(mCaches.currentProgram->getAttrib("texCoords"));
562    }
563
564    GLuint textureUnit = 0;
565    glActiveTexture(gTextureUnits[textureUnit]);
566
567    setupTextureAlpha8(fontRenderer.getTexture(), 0, 0, textureUnit, x, y, r, g, b, a,
568            mode, false, true);
569
570    const Rect& clip = mSnapshot->getLocalClip();
571    fontRenderer.renderText(paint, &clip, text, 0, bytesCount, count, x, y);
572
573    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
574    glDisableVertexAttribArray(mCaches.currentProgram->getAttrib("texCoords"));
575
576    drawTextDecorations(text, bytesCount, length, x, y, paint);
577
578    if (applyScaleX) {
579        restore();
580    }
581}
582
583void OpenGLRenderer::drawPath(SkPath* path, SkPaint* paint) {
584    if (mSnapshot->invisible) return;
585
586    GLuint textureUnit = 0;
587    glActiveTexture(gTextureUnits[textureUnit]);
588
589    const PathTexture* texture = mCaches.pathCache.get(path, paint);
590    if (!texture) return;
591    const AutoTexture autoCleanup(texture);
592
593    const float x = texture->left - texture->offset;
594    const float y = texture->top - texture->offset;
595
596    if (quickReject(x, y, x + texture->width, y + texture->height)) {
597        return;
598    }
599
600    int alpha;
601    SkXfermode::Mode mode;
602    getAlphaAndMode(paint, &alpha, &mode);
603
604    uint32_t color = paint->getColor();
605    const GLfloat a = alpha / 255.0f;
606    const GLfloat r = a * ((color >> 16) & 0xFF) / 255.0f;
607    const GLfloat g = a * ((color >>  8) & 0xFF) / 255.0f;
608    const GLfloat b = a * ((color      ) & 0xFF) / 255.0f;
609
610    setupTextureAlpha8(texture, textureUnit, x, y, r, g, b, a, mode, true, true);
611
612    // Draw the mesh
613    glDrawArrays(GL_TRIANGLE_STRIP, 0, gMeshCount);
614    glDisableVertexAttribArray(mCaches.currentProgram->getAttrib("texCoords"));
615}
616
617///////////////////////////////////////////////////////////////////////////////
618// Shaders
619///////////////////////////////////////////////////////////////////////////////
620
621void OpenGLRenderer::resetShader() {
622    mShader = NULL;
623}
624
625void OpenGLRenderer::setupShader(SkiaShader* shader) {
626    mShader = shader;
627    if (mShader) {
628        mShader->set(&mCaches.textureCache, &mCaches.gradientCache);
629    }
630}
631
632///////////////////////////////////////////////////////////////////////////////
633// Color filters
634///////////////////////////////////////////////////////////////////////////////
635
636void OpenGLRenderer::resetColorFilter() {
637    mColorFilter = NULL;
638}
639
640void OpenGLRenderer::setupColorFilter(SkiaColorFilter* filter) {
641    mColorFilter = filter;
642}
643
644///////////////////////////////////////////////////////////////////////////////
645// Drop shadow
646///////////////////////////////////////////////////////////////////////////////
647
648void OpenGLRenderer::resetShadow() {
649    mHasShadow = false;
650}
651
652void OpenGLRenderer::setupShadow(float radius, float dx, float dy, int color) {
653    mHasShadow = true;
654    mShadowRadius = radius;
655    mShadowDx = dx;
656    mShadowDy = dy;
657    mShadowColor = color;
658}
659
660///////////////////////////////////////////////////////////////////////////////
661// Drawing implementation
662///////////////////////////////////////////////////////////////////////////////
663
664void OpenGLRenderer::setupShadow(const ShadowTexture* texture, float x, float y,
665        SkXfermode::Mode mode, float alpha) {
666    const float sx = x - texture->left + mShadowDx;
667    const float sy = y - texture->top + mShadowDy;
668
669    const int shadowAlpha = ((mShadowColor >> 24) & 0xFF);
670    const GLfloat a = shadowAlpha < 255 ? shadowAlpha / 255.0f : alpha;
671    const GLfloat r = a * ((mShadowColor >> 16) & 0xFF) / 255.0f;
672    const GLfloat g = a * ((mShadowColor >>  8) & 0xFF) / 255.0f;
673    const GLfloat b = a * ((mShadowColor      ) & 0xFF) / 255.0f;
674
675    GLuint textureUnit = 0;
676    setupTextureAlpha8(texture, textureUnit, sx, sy, r, g, b, a, mode, true, false);
677}
678
679void OpenGLRenderer::setupTextureAlpha8(const Texture* texture, GLuint& textureUnit,
680        float x, float y, float r, float g, float b, float a, SkXfermode::Mode mode,
681        bool transforms, bool applyFilters) {
682    setupTextureAlpha8(texture->id, texture->width, texture->height, textureUnit,
683            x, y, r, g, b, a, mode, transforms, applyFilters);
684}
685
686void OpenGLRenderer::setupTextureAlpha8(GLuint texture, uint32_t width, uint32_t height,
687        GLuint& textureUnit, float x, float y, float r, float g, float b, float a,
688        SkXfermode::Mode mode, bool transforms, bool applyFilters) {
689     // Describe the required shaders
690     ProgramDescription description;
691     description.hasTexture = true;
692     description.hasAlpha8Texture = true;
693
694     if (applyFilters) {
695         if (mShader) {
696             mShader->describe(description, mExtensions);
697         }
698         if (mColorFilter) {
699             mColorFilter->describe(description, mExtensions);
700         }
701     }
702
703     // Build and use the appropriate shader
704     useProgram(mCaches.programCache.get(description));
705
706     // Setup the blending mode
707     chooseBlending(true, mode);
708     bindTexture(texture, GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE, textureUnit);
709     glUniform1i(mCaches.currentProgram->getUniform("sampler"), textureUnit);
710
711     int texCoordsSlot = mCaches.currentProgram->getAttrib("texCoords");
712     glEnableVertexAttribArray(texCoordsSlot);
713
714     // Setup attributes
715     glVertexAttribPointer(mCaches.currentProgram->position, 2, GL_FLOAT, GL_FALSE,
716             gMeshStride, &mMeshVertices[0].position[0]);
717     glVertexAttribPointer(texCoordsSlot, 2, GL_FLOAT, GL_FALSE,
718             gMeshStride, &mMeshVertices[0].texture[0]);
719
720     // Setup uniforms
721     if (transforms) {
722         mModelView.loadTranslate(x, y, 0.0f);
723         mModelView.scale(width, height, 1.0f);
724     } else {
725         mModelView.loadIdentity();
726     }
727     mCaches.currentProgram->set(mOrthoMatrix, mModelView, mSnapshot->transform);
728     glUniform4f(mCaches.currentProgram->color, r, g, b, a);
729
730     textureUnit++;
731     if (applyFilters) {
732         // Setup attributes and uniforms required by the shaders
733         if (mShader) {
734             mShader->setupProgram(mCaches.currentProgram, mModelView, *mSnapshot, &textureUnit);
735         }
736         if (mColorFilter) {
737             mColorFilter->setupProgram(mCaches.currentProgram);
738         }
739     }
740}
741
742#define kStdStrikeThru_Offset   (-6.0f / 21.0f)
743#define kStdUnderline_Offset    (1.0f / 9.0f)
744#define kStdUnderline_Thickness (1.0f / 18.0f)
745
746void OpenGLRenderer::drawTextDecorations(const char* text, int bytesCount, float length,
747        float x, float y, SkPaint* paint) {
748    // Handle underline and strike-through
749    uint32_t flags = paint->getFlags();
750    if (flags & (SkPaint::kUnderlineText_Flag | SkPaint::kStrikeThruText_Flag)) {
751        float underlineWidth = length;
752        // If length is > 0.0f, we already measured the text for the text alignment
753        if (length <= 0.0f) {
754            underlineWidth = paint->measureText(text, bytesCount);
755        }
756
757        float offsetX = 0;
758        switch (paint->getTextAlign()) {
759            case SkPaint::kCenter_Align:
760                offsetX = underlineWidth * 0.5f;
761                break;
762            case SkPaint::kRight_Align:
763                offsetX = underlineWidth;
764                break;
765            default:
766                break;
767        }
768
769        if (underlineWidth > 0.0f) {
770            float textSize = paint->getTextSize();
771            float height = textSize * kStdUnderline_Thickness;
772
773            float left = x - offsetX;
774            float top = 0.0f;
775            float right = left + underlineWidth;
776            float bottom = 0.0f;
777
778            if (flags & SkPaint::kUnderlineText_Flag) {
779                top = y + textSize * kStdUnderline_Offset;
780                bottom = top + height;
781                drawRect(left, top, right, bottom, paint);
782            }
783
784            if (flags & SkPaint::kStrikeThruText_Flag) {
785                top = y + textSize * kStdStrikeThru_Offset;
786                bottom = top + height;
787                drawRect(left, top, right, bottom, paint);
788            }
789        }
790    }
791}
792
793void OpenGLRenderer::drawColorRect(float left, float top, float right, float bottom,
794        int color, SkXfermode::Mode mode, bool ignoreTransform) {
795    // If a shader is set, preserve only the alpha
796    if (mShader) {
797        color |= 0x00ffffff;
798    }
799
800    // Render using pre-multiplied alpha
801    const int alpha = (color >> 24) & 0xFF;
802    const GLfloat a = alpha / 255.0f;
803    const GLfloat r = a * ((color >> 16) & 0xFF) / 255.0f;
804    const GLfloat g = a * ((color >>  8) & 0xFF) / 255.0f;
805    const GLfloat b = a * ((color      ) & 0xFF) / 255.0f;
806
807    GLuint textureUnit = 0;
808
809    // Setup the blending mode
810    chooseBlending(alpha < 255 || (mShader && mShader->blend()), mode);
811
812    // Describe the required shaders
813    ProgramDescription description;
814    if (mShader) {
815        mShader->describe(description, mExtensions);
816    }
817    if (mColorFilter) {
818        mColorFilter->describe(description, mExtensions);
819    }
820
821    // Build and use the appropriate shader
822    useProgram(mCaches.programCache.get(description));
823
824    // Setup attributes
825    glVertexAttribPointer(mCaches.currentProgram->position, 2, GL_FLOAT, GL_FALSE,
826            gMeshStride, &mMeshVertices[0].position[0]);
827
828    // Setup uniforms
829    mModelView.loadTranslate(left, top, 0.0f);
830    mModelView.scale(right - left, bottom - top, 1.0f);
831    if (!ignoreTransform) {
832        mCaches.currentProgram->set(mOrthoMatrix, mModelView, mSnapshot->transform);
833    } else {
834        mat4 identity;
835        mCaches.currentProgram->set(mOrthoMatrix, mModelView, identity);
836    }
837    glUniform4f(mCaches.currentProgram->color, r, g, b, a);
838
839    // Setup attributes and uniforms required by the shaders
840    if (mShader) {
841        mShader->setupProgram(mCaches.currentProgram, mModelView, *mSnapshot, &textureUnit);
842    }
843    if (mColorFilter) {
844        mColorFilter->setupProgram(mCaches.currentProgram);
845    }
846
847    // Draw the mesh
848    glDrawArrays(GL_TRIANGLE_STRIP, 0, gMeshCount);
849}
850
851void OpenGLRenderer::drawTextureRect(float left, float top, float right, float bottom,
852        const Texture* texture, const SkPaint* paint) {
853    int alpha;
854    SkXfermode::Mode mode;
855    getAlphaAndMode(paint, &alpha, &mode);
856
857    drawTextureMesh(left, top, right, bottom, texture->id, alpha / 255.0f, mode, texture->blend,
858            &mMeshVertices[0].position[0], &mMeshVertices[0].texture[0], NULL);
859}
860
861void OpenGLRenderer::drawTextureRect(float left, float top, float right, float bottom,
862        GLuint texture, float alpha, SkXfermode::Mode mode, bool blend) {
863    drawTextureMesh(left, top, right, bottom, texture, alpha, mode, blend,
864            &mMeshVertices[0].position[0], &mMeshVertices[0].texture[0], NULL);
865}
866
867void OpenGLRenderer::drawTextureMesh(float left, float top, float right, float bottom,
868        GLuint texture, float alpha, SkXfermode::Mode mode, bool blend,
869        GLvoid* vertices, GLvoid* texCoords, GLvoid* indices, GLsizei elementsCount) {
870    ProgramDescription description;
871    description.hasTexture = true;
872    if (mColorFilter) {
873        mColorFilter->describe(description, mExtensions);
874    }
875
876    mModelView.loadTranslate(left, top, 0.0f);
877    mModelView.scale(right - left, bottom - top, 1.0f);
878
879    useProgram(mCaches.programCache.get(description));
880    mCaches.currentProgram->set(mOrthoMatrix, mModelView, mSnapshot->transform);
881
882    chooseBlending(blend || alpha < 1.0f, mode);
883
884    // Texture
885    bindTexture(texture, GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE, 0);
886    glUniform1i(mCaches.currentProgram->getUniform("sampler"), 0);
887
888    // Always premultiplied
889    glUniform4f(mCaches.currentProgram->color, alpha, alpha, alpha, alpha);
890
891    // Mesh
892    int texCoordsSlot = mCaches.currentProgram->getAttrib("texCoords");
893    glEnableVertexAttribArray(texCoordsSlot);
894    glVertexAttribPointer(mCaches.currentProgram->position, 2, GL_FLOAT, GL_FALSE,
895            gMeshStride, vertices);
896    glVertexAttribPointer(texCoordsSlot, 2, GL_FLOAT, GL_FALSE, gMeshStride, texCoords);
897
898    // Color filter
899    if (mColorFilter) {
900        mColorFilter->setupProgram(mCaches.currentProgram);
901    }
902
903    if (!indices) {
904        glDrawArrays(GL_TRIANGLE_STRIP, 0, gMeshCount);
905    } else {
906        glDrawElements(GL_TRIANGLES, elementsCount, GL_UNSIGNED_SHORT, indices);
907    }
908    glDisableVertexAttribArray(texCoordsSlot);
909}
910
911void OpenGLRenderer::chooseBlending(bool blend, SkXfermode::Mode mode, bool isPremultiplied) {
912    blend = blend || mode != SkXfermode::kSrcOver_Mode;
913    if (blend) {
914        if (!mCaches.blend) {
915            glEnable(GL_BLEND);
916        }
917
918        GLenum sourceMode = gBlends[mode].src;
919        GLenum destMode = gBlends[mode].dst;
920        if (!isPremultiplied && sourceMode == GL_ONE) {
921            sourceMode = GL_SRC_ALPHA;
922        }
923
924        if (sourceMode != mCaches.lastSrcMode || destMode != mCaches.lastDstMode) {
925            glBlendFunc(sourceMode, destMode);
926            mCaches.lastSrcMode = sourceMode;
927            mCaches.lastDstMode = destMode;
928        }
929    } else if (mCaches.blend) {
930        glDisable(GL_BLEND);
931    }
932    mCaches.blend = blend;
933}
934
935bool OpenGLRenderer::useProgram(Program* program) {
936    if (!program->isInUse()) {
937        if (mCaches.currentProgram != NULL) mCaches.currentProgram->remove();
938        program->use();
939        mCaches.currentProgram = program;
940        return false;
941    }
942    return true;
943}
944
945void OpenGLRenderer::resetDrawTextureTexCoords(float u1, float v1, float u2, float v2) {
946    TextureVertex* v = &mMeshVertices[0];
947    TextureVertex::setUV(v++, u1, v1);
948    TextureVertex::setUV(v++, u2, v1);
949    TextureVertex::setUV(v++, u1, v2);
950    TextureVertex::setUV(v++, u2, v2);
951}
952
953void OpenGLRenderer::getAlphaAndMode(const SkPaint* paint, int* alpha, SkXfermode::Mode* mode) {
954    if (paint) {
955        const bool isMode = SkXfermode::IsMode(paint->getXfermode(), mode);
956        if (!isMode) {
957            // Assume SRC_OVER
958            *mode = SkXfermode::kSrcOver_Mode;
959        }
960
961        // Skia draws using the color's alpha channel if < 255
962        // Otherwise, it uses the paint's alpha
963        int color = paint->getColor();
964        *alpha = (color >> 24) & 0xFF;
965        if (*alpha == 255) {
966            *alpha = paint->getAlpha();
967        }
968    } else {
969        *mode = SkXfermode::kSrcOver_Mode;
970        *alpha = 255;
971    }
972}
973
974void OpenGLRenderer::bindTexture(GLuint texture, GLenum wrapS, GLenum wrapT, GLuint textureUnit) {
975    glActiveTexture(gTextureUnits[textureUnit]);
976    glBindTexture(GL_TEXTURE_2D, texture);
977    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrapS);
978    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrapT);
979}
980
981}; // namespace uirenderer
982}; // namespace android
983