1ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com/*
2ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * Copyright 2006 The Android Open Source Project
3ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com *
4ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * Use of this source code is governed by a BSD-style license that can be
5ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * found in the LICENSE file.
6ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com */
7ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com
88a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkBlitter.h"
98a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkAntiRun.h"
108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkColor.h"
118a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkColorFilter.h"
12a5572e5bb2a2bbeeb59de0741c2527869d365a0ccommit-bot@chromium.org#include "SkCoreBlitters.h"
1302f65f2d9168f2304a09d784dbcfeefb7669c8b4reed@google.com#include "SkFilterShader.h"
148b0e8ac5f582de80356019406e2975079bf0829dcommit-bot@chromium.org#include "SkReadBuffer.h"
158b0e8ac5f582de80356019406e2975079bf0829dcommit-bot@chromium.org#include "SkWriteBuffer.h"
168a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkMask.h"
178a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkMaskFilter.h"
18a5572e5bb2a2bbeeb59de0741c2527869d365a0ccommit-bot@chromium.org#include "SkString.h"
19458849004892c05fa1dcbcf6d355dfcce028d77areed@google.com#include "SkTLazy.h"
208a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkUtils.h"
218a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkXfermode.h"
228a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
23845fdaca174f4675e9acc164b510e3a5ffa9053creed@android.comSkBlitter::~SkBlitter() {}
248a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
25ea033606a06d05d2d42aa7118409fee798e53167reed@google.combool SkBlitter::isNullBlitter() const { return false; }
26ea033606a06d05d2d42aa7118409fee798e53167reed@google.com
2780116dcf1e1baf9817ae42d0aca51f7eabaa2880commit-bot@chromium.orgbool SkBlitter::resetShaderContext(const SkShader::ContextRec&) {
2887fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org    return true;
2987fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org}
3087fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org
3187fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.orgSkShader::Context* SkBlitter::getShaderContext() const {
3287fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org    return NULL;
3387fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org}
3487fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org
3582065d667f64e232bcde2ad849756a6096fcbe6freed@google.comconst SkBitmap* SkBlitter::justAnOpaqueColor(uint32_t* value) {
368a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return NULL;
378a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
388a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
3982065d667f64e232bcde2ad849756a6096fcbe6freed@google.comvoid SkBlitter::blitH(int x, int y, int width) {
400c00f21fee3f5cfa3aa7e5d46ff94cb8cf340451tomhudson@google.com    SkDEBUGFAIL("unimplemented");
418a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
428a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
4382065d667f64e232bcde2ad849756a6096fcbe6freed@google.comvoid SkBlitter::blitAntiH(int x, int y, const SkAlpha antialias[],
4482065d667f64e232bcde2ad849756a6096fcbe6freed@google.com                          const int16_t runs[]) {
450c00f21fee3f5cfa3aa7e5d46ff94cb8cf340451tomhudson@google.com    SkDEBUGFAIL("unimplemented");
468a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
478a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
4882065d667f64e232bcde2ad849756a6096fcbe6freed@google.comvoid SkBlitter::blitV(int x, int y, int height, SkAlpha alpha) {
4982065d667f64e232bcde2ad849756a6096fcbe6freed@google.com    if (alpha == 255) {
508a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        this->blitRect(x, y, 1, height);
5182065d667f64e232bcde2ad849756a6096fcbe6freed@google.com    } else {
528a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        int16_t runs[2];
538a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        runs[0] = 1;
548a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        runs[1] = 0;
558a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
5682065d667f64e232bcde2ad849756a6096fcbe6freed@google.com        while (--height >= 0) {
578a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            this->blitAntiH(x, y++, &alpha, runs);
5882065d667f64e232bcde2ad849756a6096fcbe6freed@google.com        }
598a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
608a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
618a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
6282065d667f64e232bcde2ad849756a6096fcbe6freed@google.comvoid SkBlitter::blitRect(int x, int y, int width, int height) {
63a31ac73b8e261f02c4bd6ae1d622c4bd00226b80tomhudson@google.com    SkASSERT(width > 0);
6482065d667f64e232bcde2ad849756a6096fcbe6freed@google.com    while (--height >= 0) {
658a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        this->blitH(x, y++, width);
6682065d667f64e232bcde2ad849756a6096fcbe6freed@google.com    }
678a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
688a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
6949eac192faa35159752525b23345563252721c64tomhudson@google.com/// Default implementation doesn't check for any easy optimizations
7049eac192faa35159752525b23345563252721c64tomhudson@google.com/// such as alpha == 0 or 255; also uses blitV(), which some subclasses
7149eac192faa35159752525b23345563252721c64tomhudson@google.com/// may not support.
7249eac192faa35159752525b23345563252721c64tomhudson@google.comvoid SkBlitter::blitAntiRect(int x, int y, int width, int height,
7349eac192faa35159752525b23345563252721c64tomhudson@google.com                             SkAlpha leftAlpha, SkAlpha rightAlpha) {
744714359ec091b34a4f88eb9708868a58a22177d3tomhudson@google.com    this->blitV(x++, y, height, leftAlpha);
75a31ac73b8e261f02c4bd6ae1d622c4bd00226b80tomhudson@google.com    if (width > 0) {
764714359ec091b34a4f88eb9708868a58a22177d3tomhudson@google.com        this->blitRect(x, y, width, height);
774714359ec091b34a4f88eb9708868a58a22177d3tomhudson@google.com        x += width;
784714359ec091b34a4f88eb9708868a58a22177d3tomhudson@google.com    }
794714359ec091b34a4f88eb9708868a58a22177d3tomhudson@google.com    this->blitV(x, y, height, rightAlpha);
8049eac192faa35159752525b23345563252721c64tomhudson@google.com}
8149eac192faa35159752525b23345563252721c64tomhudson@google.com
828a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com//////////////////////////////////////////////////////////////////////////////
838a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
8482065d667f64e232bcde2ad849756a6096fcbe6freed@google.comstatic inline void bits_to_runs(SkBlitter* blitter, int x, int y,
8582065d667f64e232bcde2ad849756a6096fcbe6freed@google.com                                const uint8_t bits[],
8682065d667f64e232bcde2ad849756a6096fcbe6freed@google.com                                U8CPU left_mask, int rowBytes,
8782065d667f64e232bcde2ad849756a6096fcbe6freed@google.com                                U8CPU right_mask) {
888a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    int inFill = 0;
898a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    int pos = 0;
908a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
9182065d667f64e232bcde2ad849756a6096fcbe6freed@google.com    while (--rowBytes >= 0) {
928a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        unsigned b = *bits++ & left_mask;
9382065d667f64e232bcde2ad849756a6096fcbe6freed@google.com        if (rowBytes == 0) {
948a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            b &= right_mask;
9582065d667f64e232bcde2ad849756a6096fcbe6freed@google.com        }
968a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
9782065d667f64e232bcde2ad849756a6096fcbe6freed@google.com        for (unsigned test = 0x80; test != 0; test >>= 1) {
9882065d667f64e232bcde2ad849756a6096fcbe6freed@google.com            if (b & test) {
9982065d667f64e232bcde2ad849756a6096fcbe6freed@google.com                if (!inFill) {
1008a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                    pos = x;
1018a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                    inFill = true;
1028a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                }
10382065d667f64e232bcde2ad849756a6096fcbe6freed@google.com            } else {
10482065d667f64e232bcde2ad849756a6096fcbe6freed@google.com                if (inFill) {
1058a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                    blitter->blitH(pos, y, x - pos);
1068a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                    inFill = false;
1078a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                }
1088a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            }
1098a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            x += 1;
1108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
1118a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        left_mask = 0xFF;
1128a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
1138a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1148a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    // final cleanup
11582065d667f64e232bcde2ad849756a6096fcbe6freed@google.com    if (inFill) {
1168a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        blitter->blitH(pos, y, x - pos);
11782065d667f64e232bcde2ad849756a6096fcbe6freed@google.com    }
1188a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
1198a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
12082065d667f64e232bcde2ad849756a6096fcbe6freed@google.comvoid SkBlitter::blitMask(const SkMask& mask, const SkIRect& clip) {
1218a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkASSERT(mask.fBounds.contains(clip));
1228a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
12382065d667f64e232bcde2ad849756a6096fcbe6freed@google.com    if (mask.fFormat == SkMask::kBW_Format) {
1248a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        int cx = clip.fLeft;
1258a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        int cy = clip.fTop;
1268a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        int maskLeft = mask.fBounds.fLeft;
1278a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        int mask_rowBytes = mask.fRowBytes;
1288a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        int height = clip.height();
1298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        const uint8_t* bits = mask.getAddr1(cx, cy);
1318a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
13282065d667f64e232bcde2ad849756a6096fcbe6freed@google.com        if (cx == maskLeft && clip.fRight == mask.fBounds.fRight) {
13382065d667f64e232bcde2ad849756a6096fcbe6freed@google.com            while (--height >= 0) {
1348a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                bits_to_runs(this, cx, cy, bits, 0xFF, mask_rowBytes, 0xFF);
1358a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                bits += mask_rowBytes;
1368a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                cy += 1;
1378a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            }
13882065d667f64e232bcde2ad849756a6096fcbe6freed@google.com        } else {
1398a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            int left_edge = cx - maskLeft;
1408a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            SkASSERT(left_edge >= 0);
1418a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            int rite_edge = clip.fRight - maskLeft;
1428a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            SkASSERT(rite_edge > left_edge);
1438a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1448a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            int left_mask = 0xFF >> (left_edge & 7);
1458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            int rite_mask = 0xFF << (8 - (rite_edge & 7));
1468a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            int full_runs = (rite_edge >> 3) - ((left_edge + 7) >> 3);
1478a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
148a89c77b5cafcc13d76cb07c3240e48705cb30d8freed@google.com            // check for empty right mask, so we don't read off the end (or go slower than we need to)
14982065d667f64e232bcde2ad849756a6096fcbe6freed@google.com            if (rite_mask == 0) {
1508a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                SkASSERT(full_runs >= 0);
1518a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                full_runs -= 1;
1528a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                rite_mask = 0xFF;
1538a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            }
15482065d667f64e232bcde2ad849756a6096fcbe6freed@google.com            if (left_mask == 0xFF) {
1558a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                full_runs -= 1;
15682065d667f64e232bcde2ad849756a6096fcbe6freed@google.com            }
1578a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
158a89c77b5cafcc13d76cb07c3240e48705cb30d8freed@google.com            // back up manually so we can keep in sync with our byte-aligned src
159a89c77b5cafcc13d76cb07c3240e48705cb30d8freed@google.com            // have cx reflect our actual starting x-coord
1608a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            cx -= left_edge & 7;
1618a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
16282065d667f64e232bcde2ad849756a6096fcbe6freed@google.com            if (full_runs < 0) {
1638a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                SkASSERT((left_mask & rite_mask) != 0);
16482065d667f64e232bcde2ad849756a6096fcbe6freed@google.com                while (--height >= 0) {
1658a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                    bits_to_runs(this, cx, cy, bits, left_mask, 1, rite_mask);
1668a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                    bits += mask_rowBytes;
1678a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                    cy += 1;
1688a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                }
16982065d667f64e232bcde2ad849756a6096fcbe6freed@google.com            } else {
17082065d667f64e232bcde2ad849756a6096fcbe6freed@google.com                while (--height >= 0) {
171a89c77b5cafcc13d76cb07c3240e48705cb30d8freed@google.com                    bits_to_runs(this, cx, cy, bits, left_mask, full_runs + 2, rite_mask);
1728a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                    bits += mask_rowBytes;
1738a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                    cy += 1;
1748a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                }
1758a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            }
1768a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
17782065d667f64e232bcde2ad849756a6096fcbe6freed@google.com    } else {
1788a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        int                         width = clip.width();
1798a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkAutoSTMalloc<64, int16_t> runStorage(width + 1);
1808a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        int16_t*                    runs = runStorage.get();
1817989186dab6bc2f1c1927daf91bddd32b7fd8d0creed@google.com        const uint8_t*              aa = mask.getAddr8(clip.fLeft, clip.fTop);
1828a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1838a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        sk_memset16((uint16_t*)runs, 1, width);
1848a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        runs[width] = 0;
1858a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1868a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        int height = clip.height();
1878a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        int y = clip.fTop;
18882065d667f64e232bcde2ad849756a6096fcbe6freed@google.com        while (--height >= 0) {
1898a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            this->blitAntiH(clip.fLeft, y, aa, runs);
1908a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            aa += mask.fRowBytes;
1918a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            y += 1;
1928a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
1938a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
1948a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
1958a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1968a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com/////////////////////// these guys are not virtual, just a helpers
1978a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1988a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid SkBlitter::blitMaskRegion(const SkMask& mask, const SkRegion& clip) {
1998a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (clip.quickReject(mask.fBounds)) {
2008a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return;
2018a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
20282065d667f64e232bcde2ad849756a6096fcbe6freed@google.com
2038a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkRegion::Cliperator clipper(clip, mask.fBounds);
20482065d667f64e232bcde2ad849756a6096fcbe6freed@google.com
2058a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    while (!clipper.done()) {
2068a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        const SkIRect& cr = clipper.rect();
2078a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        this->blitMask(mask, cr);
2088a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        clipper.next();
2098a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
2108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
2118a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
2128a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid SkBlitter::blitRectRegion(const SkIRect& rect, const SkRegion& clip) {
2138a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkRegion::Cliperator clipper(clip, rect);
21482065d667f64e232bcde2ad849756a6096fcbe6freed@google.com
2158a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    while (!clipper.done()) {
2168a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        const SkIRect& cr = clipper.rect();
2178a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        this->blitRect(cr.fLeft, cr.fTop, cr.width(), cr.height());
2188a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        clipper.next();
2198a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
2208a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
2218a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
2228a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid SkBlitter::blitRegion(const SkRegion& clip) {
2238a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkRegion::Iterator iter(clip);
22482065d667f64e232bcde2ad849756a6096fcbe6freed@google.com
2258a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    while (!iter.done()) {
2268a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        const SkIRect& cr = iter.rect();
2278a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        this->blitRect(cr.fLeft, cr.fTop, cr.width(), cr.height());
2288a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        iter.next();
2298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
2308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
2318a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
23282065d667f64e232bcde2ad849756a6096fcbe6freed@google.com///////////////////////////////////////////////////////////////////////////////
2338a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
23482065d667f64e232bcde2ad849756a6096fcbe6freed@google.comvoid SkNullBlitter::blitH(int x, int y, int width) {}
2358a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
23682065d667f64e232bcde2ad849756a6096fcbe6freed@google.comvoid SkNullBlitter::blitAntiH(int x, int y, const SkAlpha antialias[],
23782065d667f64e232bcde2ad849756a6096fcbe6freed@google.com                              const int16_t runs[]) {}
2388a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
23982065d667f64e232bcde2ad849756a6096fcbe6freed@google.comvoid SkNullBlitter::blitV(int x, int y, int height, SkAlpha alpha) {}
2408a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
24182065d667f64e232bcde2ad849756a6096fcbe6freed@google.comvoid SkNullBlitter::blitRect(int x, int y, int width, int height) {}
2428a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
24382065d667f64e232bcde2ad849756a6096fcbe6freed@google.comvoid SkNullBlitter::blitMask(const SkMask& mask, const SkIRect& clip) {}
2448a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
24582065d667f64e232bcde2ad849756a6096fcbe6freed@google.comconst SkBitmap* SkNullBlitter::justAnOpaqueColor(uint32_t* value) {
2468a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return NULL;
2478a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
2488a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
249ea033606a06d05d2d42aa7118409fee798e53167reed@google.combool SkNullBlitter::isNullBlitter() const { return true; }
250ea033606a06d05d2d42aa7118409fee798e53167reed@google.com
25182065d667f64e232bcde2ad849756a6096fcbe6freed@google.com///////////////////////////////////////////////////////////////////////////////
2528a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
25382065d667f64e232bcde2ad849756a6096fcbe6freed@google.comstatic int compute_anti_width(const int16_t runs[]) {
2548a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    int width = 0;
25582065d667f64e232bcde2ad849756a6096fcbe6freed@google.com
25682065d667f64e232bcde2ad849756a6096fcbe6freed@google.com    for (;;) {
2578a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        int count = runs[0];
25882065d667f64e232bcde2ad849756a6096fcbe6freed@google.com
2598a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkASSERT(count >= 0);
26082065d667f64e232bcde2ad849756a6096fcbe6freed@google.com        if (count == 0) {
2618a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            break;
26282065d667f64e232bcde2ad849756a6096fcbe6freed@google.com        }
2638a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        width += count;
2648a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        runs += count;
2658a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
2668a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return width;
2678a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
2688a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
26982065d667f64e232bcde2ad849756a6096fcbe6freed@google.comstatic inline bool y_in_rect(int y, const SkIRect& rect) {
2708a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return (unsigned)(y - rect.fTop) < (unsigned)rect.height();
2718a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
2728a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
27382065d667f64e232bcde2ad849756a6096fcbe6freed@google.comstatic inline bool x_in_rect(int x, const SkIRect& rect) {
2748a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return (unsigned)(x - rect.fLeft) < (unsigned)rect.width();
2758a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
2768a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
27782065d667f64e232bcde2ad849756a6096fcbe6freed@google.comvoid SkRectClipBlitter::blitH(int left, int y, int width) {
2788a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkASSERT(width > 0);
2798a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
28082065d667f64e232bcde2ad849756a6096fcbe6freed@google.com    if (!y_in_rect(y, fClipRect)) {
2818a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return;
28282065d667f64e232bcde2ad849756a6096fcbe6freed@google.com    }
2838a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
2848a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    int right = left + width;
2858a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
28682065d667f64e232bcde2ad849756a6096fcbe6freed@google.com    if (left < fClipRect.fLeft) {
2878a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        left = fClipRect.fLeft;
28882065d667f64e232bcde2ad849756a6096fcbe6freed@google.com    }
28982065d667f64e232bcde2ad849756a6096fcbe6freed@google.com    if (right > fClipRect.fRight) {
2908a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        right = fClipRect.fRight;
29182065d667f64e232bcde2ad849756a6096fcbe6freed@google.com    }
2928a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
2938a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    width = right - left;
29482065d667f64e232bcde2ad849756a6096fcbe6freed@google.com    if (width > 0) {
2958a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        fBlitter->blitH(left, y, width);
29682065d667f64e232bcde2ad849756a6096fcbe6freed@google.com    }
2978a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
2988a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
29982065d667f64e232bcde2ad849756a6096fcbe6freed@google.comvoid SkRectClipBlitter::blitAntiH(int left, int y, const SkAlpha aa[],
30082065d667f64e232bcde2ad849756a6096fcbe6freed@google.com                                  const int16_t runs[]) {
30182065d667f64e232bcde2ad849756a6096fcbe6freed@google.com    if (!y_in_rect(y, fClipRect) || left >= fClipRect.fRight) {
3028a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return;
30382065d667f64e232bcde2ad849756a6096fcbe6freed@google.com    }
3048a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
3058a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    int x0 = left;
3068a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    int x1 = left + compute_anti_width(runs);
3078a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
30882065d667f64e232bcde2ad849756a6096fcbe6freed@google.com    if (x1 <= fClipRect.fLeft) {
3098a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return;
31082065d667f64e232bcde2ad849756a6096fcbe6freed@google.com    }
3118a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
3128a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkASSERT(x0 < x1);
31382065d667f64e232bcde2ad849756a6096fcbe6freed@google.com    if (x0 < fClipRect.fLeft) {
3148a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        int dx = fClipRect.fLeft - x0;
3158a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkAlphaRuns::BreakAt((int16_t*)runs, (uint8_t*)aa, dx);
3168a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        runs += dx;
3178a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        aa += dx;
3188a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        x0 = fClipRect.fLeft;
3198a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
3208a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
3218a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkASSERT(x0 < x1 && runs[x1 - x0] == 0);
32282065d667f64e232bcde2ad849756a6096fcbe6freed@google.com    if (x1 > fClipRect.fRight) {
3238a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        x1 = fClipRect.fRight;
3248a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkAlphaRuns::BreakAt((int16_t*)runs, (uint8_t*)aa, x1 - x0);
3258a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        ((int16_t*)runs)[x1 - x0] = 0;
3268a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
3278a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
3288a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkASSERT(x0 < x1 && runs[x1 - x0] == 0);
3298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkASSERT(compute_anti_width(runs) == x1 - x0);
3308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
3318a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fBlitter->blitAntiH(x0, y, aa, runs);
3328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
3338a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
33482065d667f64e232bcde2ad849756a6096fcbe6freed@google.comvoid SkRectClipBlitter::blitV(int x, int y, int height, SkAlpha alpha) {
3358a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkASSERT(height > 0);
3368a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
33782065d667f64e232bcde2ad849756a6096fcbe6freed@google.com    if (!x_in_rect(x, fClipRect)) {
3388a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return;
33982065d667f64e232bcde2ad849756a6096fcbe6freed@google.com    }
3408a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
3418a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    int y0 = y;
3428a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    int y1 = y + height;
3438a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
34482065d667f64e232bcde2ad849756a6096fcbe6freed@google.com    if (y0 < fClipRect.fTop) {
3458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        y0 = fClipRect.fTop;
34682065d667f64e232bcde2ad849756a6096fcbe6freed@google.com    }
34782065d667f64e232bcde2ad849756a6096fcbe6freed@google.com    if (y1 > fClipRect.fBottom) {
3488a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        y1 = fClipRect.fBottom;
34982065d667f64e232bcde2ad849756a6096fcbe6freed@google.com    }
3508a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
35182065d667f64e232bcde2ad849756a6096fcbe6freed@google.com    if (y0 < y1) {
3528a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        fBlitter->blitV(x, y0, y1 - y0, alpha);
35382065d667f64e232bcde2ad849756a6096fcbe6freed@google.com    }
3548a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
3558a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
35682065d667f64e232bcde2ad849756a6096fcbe6freed@google.comvoid SkRectClipBlitter::blitRect(int left, int y, int width, int height) {
3578a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkIRect    r;
3588a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
3598a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    r.set(left, y, left + width, y + height);
36082065d667f64e232bcde2ad849756a6096fcbe6freed@google.com    if (r.intersect(fClipRect)) {
3618a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        fBlitter->blitRect(r.fLeft, r.fTop, r.width(), r.height());
36282065d667f64e232bcde2ad849756a6096fcbe6freed@google.com    }
3638a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
3648a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
36549eac192faa35159752525b23345563252721c64tomhudson@google.comvoid SkRectClipBlitter::blitAntiRect(int left, int y, int width, int height,
36649eac192faa35159752525b23345563252721c64tomhudson@google.com                                     SkAlpha leftAlpha, SkAlpha rightAlpha) {
36749eac192faa35159752525b23345563252721c64tomhudson@google.com    SkIRect    r;
36849eac192faa35159752525b23345563252721c64tomhudson@google.com
36949eac192faa35159752525b23345563252721c64tomhudson@google.com    // The *true* width of the rectangle blitted is width+2:
37049eac192faa35159752525b23345563252721c64tomhudson@google.com    r.set(left, y, left + width + 2, y + height);
37149eac192faa35159752525b23345563252721c64tomhudson@google.com    if (r.intersect(fClipRect)) {
37249eac192faa35159752525b23345563252721c64tomhudson@google.com        if (r.fLeft != left) {
37349eac192faa35159752525b23345563252721c64tomhudson@google.com            SkASSERT(r.fLeft > left);
37449eac192faa35159752525b23345563252721c64tomhudson@google.com            leftAlpha = 255;
37549eac192faa35159752525b23345563252721c64tomhudson@google.com        }
37649eac192faa35159752525b23345563252721c64tomhudson@google.com        if (r.fRight != left + width + 2) {
37749eac192faa35159752525b23345563252721c64tomhudson@google.com            SkASSERT(r.fRight < left + width + 2);
37849eac192faa35159752525b23345563252721c64tomhudson@google.com            rightAlpha = 255;
37949eac192faa35159752525b23345563252721c64tomhudson@google.com        }
38049eac192faa35159752525b23345563252721c64tomhudson@google.com        if (255 == leftAlpha && 255 == rightAlpha) {
38149eac192faa35159752525b23345563252721c64tomhudson@google.com            fBlitter->blitRect(r.fLeft, r.fTop, r.width(), r.height());
38249eac192faa35159752525b23345563252721c64tomhudson@google.com        } else if (1 == r.width()) {
38349eac192faa35159752525b23345563252721c64tomhudson@google.com            if (r.fLeft == left) {
38449eac192faa35159752525b23345563252721c64tomhudson@google.com                fBlitter->blitV(r.fLeft, r.fTop, r.height(), leftAlpha);
38549eac192faa35159752525b23345563252721c64tomhudson@google.com            } else {
38649eac192faa35159752525b23345563252721c64tomhudson@google.com                SkASSERT(r.fLeft == left + width + 1);
38749eac192faa35159752525b23345563252721c64tomhudson@google.com                fBlitter->blitV(r.fLeft, r.fTop, r.height(), rightAlpha);
38849eac192faa35159752525b23345563252721c64tomhudson@google.com            }
38949eac192faa35159752525b23345563252721c64tomhudson@google.com        } else {
39049eac192faa35159752525b23345563252721c64tomhudson@google.com            fBlitter->blitAntiRect(r.fLeft, r.fTop, r.width() - 2, r.height(),
39149eac192faa35159752525b23345563252721c64tomhudson@google.com                                   leftAlpha, rightAlpha);
39249eac192faa35159752525b23345563252721c64tomhudson@google.com        }
39349eac192faa35159752525b23345563252721c64tomhudson@google.com    }
39449eac192faa35159752525b23345563252721c64tomhudson@google.com}
39549eac192faa35159752525b23345563252721c64tomhudson@google.com
39682065d667f64e232bcde2ad849756a6096fcbe6freed@google.comvoid SkRectClipBlitter::blitMask(const SkMask& mask, const SkIRect& clip) {
3978a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkASSERT(mask.fBounds.contains(clip));
3988a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
3998a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkIRect    r = clip;
4008a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
40182065d667f64e232bcde2ad849756a6096fcbe6freed@google.com    if (r.intersect(fClipRect)) {
4028a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        fBlitter->blitMask(mask, r);
40382065d667f64e232bcde2ad849756a6096fcbe6freed@google.com    }
4048a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
4058a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
40682065d667f64e232bcde2ad849756a6096fcbe6freed@google.comconst SkBitmap* SkRectClipBlitter::justAnOpaqueColor(uint32_t* value) {
4078a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return fBlitter->justAnOpaqueColor(value);
4088a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
4098a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
41082065d667f64e232bcde2ad849756a6096fcbe6freed@google.com///////////////////////////////////////////////////////////////////////////////
4118a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
41282065d667f64e232bcde2ad849756a6096fcbe6freed@google.comvoid SkRgnClipBlitter::blitH(int x, int y, int width) {
4138a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkRegion::Spanerator span(*fRgn, y, x, x + width);
4148a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    int left, right;
4158a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
41682065d667f64e232bcde2ad849756a6096fcbe6freed@google.com    while (span.next(&left, &right)) {
4178a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkASSERT(left < right);
4188a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        fBlitter->blitH(left, y, right - left);
4198a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
4208a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
4218a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
42282065d667f64e232bcde2ad849756a6096fcbe6freed@google.comvoid SkRgnClipBlitter::blitAntiH(int x, int y, const SkAlpha aa[],
42382065d667f64e232bcde2ad849756a6096fcbe6freed@google.com                                 const int16_t runs[]) {
4248a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    int width = compute_anti_width(runs);
4258a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkRegion::Spanerator span(*fRgn, y, x, x + width);
4268a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    int left, right;
4278a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkDEBUGCODE(const SkIRect& bounds = fRgn->getBounds();)
42882065d667f64e232bcde2ad849756a6096fcbe6freed@google.com
4298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    int prevRite = x;
43082065d667f64e232bcde2ad849756a6096fcbe6freed@google.com    while (span.next(&left, &right)) {
4318a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkASSERT(x <= left);
4328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkASSERT(left < right);
4338a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkASSERT(left >= bounds.fLeft && right <= bounds.fRight);
43482065d667f64e232bcde2ad849756a6096fcbe6freed@google.com
4358a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkAlphaRuns::Break((int16_t*)runs, (uint8_t*)aa, left - x, right - left);
4368a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
4378a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        // now zero before left
43882065d667f64e232bcde2ad849756a6096fcbe6freed@google.com        if (left > prevRite) {
4398a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            int index = prevRite - x;
4408a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            ((uint8_t*)aa)[index] = 0;   // skip runs after right
4418a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            ((int16_t*)runs)[index] = SkToS16(left - prevRite);
4428a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
44382065d667f64e232bcde2ad849756a6096fcbe6freed@google.com
4448a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        prevRite = right;
4458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
44682065d667f64e232bcde2ad849756a6096fcbe6freed@google.com
44782065d667f64e232bcde2ad849756a6096fcbe6freed@google.com    if (prevRite > x) {
4488a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        ((int16_t*)runs)[prevRite - x] = 0;
44982065d667f64e232bcde2ad849756a6096fcbe6freed@google.com
4508a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        if (x < 0) {
4518a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            int skip = runs[0];
4528a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            SkASSERT(skip >= -x);
4538a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            aa += skip;
4548a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            runs += skip;
4558a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            x += skip;
4568a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
4578a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        fBlitter->blitAntiH(x, y, aa, runs);
4588a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
4598a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
4608a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
46182065d667f64e232bcde2ad849756a6096fcbe6freed@google.comvoid SkRgnClipBlitter::blitV(int x, int y, int height, SkAlpha alpha) {
4628a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkIRect    bounds;
4638a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    bounds.set(x, y, x + 1, y + height);
4648a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
4658a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkRegion::Cliperator    iter(*fRgn, bounds);
4668a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
46782065d667f64e232bcde2ad849756a6096fcbe6freed@google.com    while (!iter.done()) {
4688a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        const SkIRect& r = iter.rect();
4698a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkASSERT(bounds.contains(r));
4708a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
4718a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        fBlitter->blitV(x, r.fTop, r.height(), alpha);
4728a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        iter.next();
4738a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
4748a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
4758a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
47682065d667f64e232bcde2ad849756a6096fcbe6freed@google.comvoid SkRgnClipBlitter::blitRect(int x, int y, int width, int height) {
4778a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkIRect    bounds;
4788a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    bounds.set(x, y, x + width, y + height);
4798a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
4808a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkRegion::Cliperator    iter(*fRgn, bounds);
4818a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
48282065d667f64e232bcde2ad849756a6096fcbe6freed@google.com    while (!iter.done()) {
4838a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        const SkIRect& r = iter.rect();
4848a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkASSERT(bounds.contains(r));
4858a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
4868a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        fBlitter->blitRect(r.fLeft, r.fTop, r.width(), r.height());
4878a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        iter.next();
4888a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
4898a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
4908a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
49149eac192faa35159752525b23345563252721c64tomhudson@google.comvoid SkRgnClipBlitter::blitAntiRect(int x, int y, int width, int height,
49249eac192faa35159752525b23345563252721c64tomhudson@google.com                                    SkAlpha leftAlpha, SkAlpha rightAlpha) {
49349eac192faa35159752525b23345563252721c64tomhudson@google.com    // The *true* width of the rectangle to blit is width + 2
49449eac192faa35159752525b23345563252721c64tomhudson@google.com    SkIRect    bounds;
49549eac192faa35159752525b23345563252721c64tomhudson@google.com    bounds.set(x, y, x + width + 2, y + height);
49649eac192faa35159752525b23345563252721c64tomhudson@google.com
49749eac192faa35159752525b23345563252721c64tomhudson@google.com    SkRegion::Cliperator    iter(*fRgn, bounds);
49849eac192faa35159752525b23345563252721c64tomhudson@google.com
49949eac192faa35159752525b23345563252721c64tomhudson@google.com    while (!iter.done()) {
50049eac192faa35159752525b23345563252721c64tomhudson@google.com        const SkIRect& r = iter.rect();
50149eac192faa35159752525b23345563252721c64tomhudson@google.com        SkASSERT(bounds.contains(r));
50249eac192faa35159752525b23345563252721c64tomhudson@google.com        SkASSERT(r.fLeft >= x);
50331bab3934c773c2bd4c1e5e9ba8eb87c1c623b09tomhudson@google.com        SkASSERT(r.fRight <= x + width + 2);
50449eac192faa35159752525b23345563252721c64tomhudson@google.com
50549eac192faa35159752525b23345563252721c64tomhudson@google.com        SkAlpha effectiveLeftAlpha = (r.fLeft == x) ? leftAlpha : 255;
50649eac192faa35159752525b23345563252721c64tomhudson@google.com        SkAlpha effectiveRightAlpha = (r.fRight == x + width + 2) ?
50749eac192faa35159752525b23345563252721c64tomhudson@google.com                                      rightAlpha : 255;
50849eac192faa35159752525b23345563252721c64tomhudson@google.com
50949eac192faa35159752525b23345563252721c64tomhudson@google.com        if (255 == effectiveLeftAlpha && 255 == effectiveRightAlpha) {
51049eac192faa35159752525b23345563252721c64tomhudson@google.com            fBlitter->blitRect(r.fLeft, r.fTop, r.width(), r.height());
51149eac192faa35159752525b23345563252721c64tomhudson@google.com        } else if (1 == r.width()) {
51249eac192faa35159752525b23345563252721c64tomhudson@google.com            if (r.fLeft == x) {
513fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com                fBlitter->blitV(r.fLeft, r.fTop, r.height(),
51449eac192faa35159752525b23345563252721c64tomhudson@google.com                                effectiveLeftAlpha);
51549eac192faa35159752525b23345563252721c64tomhudson@google.com            } else {
51649eac192faa35159752525b23345563252721c64tomhudson@google.com                SkASSERT(r.fLeft == x + width + 1);
51749eac192faa35159752525b23345563252721c64tomhudson@google.com                fBlitter->blitV(r.fLeft, r.fTop, r.height(),
51849eac192faa35159752525b23345563252721c64tomhudson@google.com                                effectiveRightAlpha);
51949eac192faa35159752525b23345563252721c64tomhudson@google.com            }
52049eac192faa35159752525b23345563252721c64tomhudson@google.com        } else {
52149eac192faa35159752525b23345563252721c64tomhudson@google.com            fBlitter->blitAntiRect(r.fLeft, r.fTop, r.width() - 2, r.height(),
52249eac192faa35159752525b23345563252721c64tomhudson@google.com                                   effectiveLeftAlpha, effectiveRightAlpha);
52349eac192faa35159752525b23345563252721c64tomhudson@google.com        }
52449eac192faa35159752525b23345563252721c64tomhudson@google.com        iter.next();
52549eac192faa35159752525b23345563252721c64tomhudson@google.com    }
52649eac192faa35159752525b23345563252721c64tomhudson@google.com}
52749eac192faa35159752525b23345563252721c64tomhudson@google.com
52849eac192faa35159752525b23345563252721c64tomhudson@google.com
52982065d667f64e232bcde2ad849756a6096fcbe6freed@google.comvoid SkRgnClipBlitter::blitMask(const SkMask& mask, const SkIRect& clip) {
5308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkASSERT(mask.fBounds.contains(clip));
5318a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
5328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkRegion::Cliperator iter(*fRgn, clip);
5338a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    const SkIRect&       r = iter.rect();
5348a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkBlitter*           blitter = fBlitter;
5358a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
53682065d667f64e232bcde2ad849756a6096fcbe6freed@google.com    while (!iter.done()) {
5378a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        blitter->blitMask(mask, r);
5388a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        iter.next();
5398a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
5408a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
5418a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
54282065d667f64e232bcde2ad849756a6096fcbe6freed@google.comconst SkBitmap* SkRgnClipBlitter::justAnOpaqueColor(uint32_t* value) {
5438a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return fBlitter->justAnOpaqueColor(value);
5448a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
5458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
54682065d667f64e232bcde2ad849756a6096fcbe6freed@google.com///////////////////////////////////////////////////////////////////////////////
5478a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
54882065d667f64e232bcde2ad849756a6096fcbe6freed@google.comSkBlitter* SkBlitterClipper::apply(SkBlitter* blitter, const SkRegion* clip,
54982065d667f64e232bcde2ad849756a6096fcbe6freed@google.com                                   const SkIRect* ir) {
55082065d667f64e232bcde2ad849756a6096fcbe6freed@google.com    if (clip) {
5518a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        const SkIRect& clipR = clip->getBounds();
5528a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
55382065d667f64e232bcde2ad849756a6096fcbe6freed@google.com        if (clip->isEmpty() || (ir && !SkIRect::Intersects(clipR, *ir))) {
5548a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            blitter = &fNullBlitter;
55582065d667f64e232bcde2ad849756a6096fcbe6freed@google.com        } else if (clip->isRect()) {
55682065d667f64e232bcde2ad849756a6096fcbe6freed@google.com            if (ir == NULL || !clipR.contains(*ir)) {
5578a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                fRectBlitter.init(blitter, clipR);
5588a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                blitter = &fRectBlitter;
5598a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            }
56082065d667f64e232bcde2ad849756a6096fcbe6freed@google.com        } else {
5618a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            fRgnBlitter.init(blitter, clip);
5628a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            blitter = &fRgnBlitter;
5638a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
5648a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
5658a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return blitter;
5668a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
5678a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
56882065d667f64e232bcde2ad849756a6096fcbe6freed@google.com///////////////////////////////////////////////////////////////////////////////
5698a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
5708a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkColorShader.h"
5718a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkColorPriv.h"
5728a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
5738a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comclass Sk3DShader : public SkShader {
5748a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.compublic:
57582065d667f64e232bcde2ad849756a6096fcbe6freed@google.com    Sk3DShader(SkShader* proxy) : fProxy(proxy) {
57682065d667f64e232bcde2ad849756a6096fcbe6freed@google.com        SkSafeRef(proxy);
5778a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
57882065d667f64e232bcde2ad849756a6096fcbe6freed@google.com
57982065d667f64e232bcde2ad849756a6096fcbe6freed@google.com    virtual ~Sk3DShader() {
58082065d667f64e232bcde2ad849756a6096fcbe6freed@google.com        SkSafeUnref(fProxy);
5818a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
58282065d667f64e232bcde2ad849756a6096fcbe6freed@google.com
58387fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org    virtual size_t contextSize() const SK_OVERRIDE {
58487fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org        size_t size = sizeof(Sk3DShaderContext);
58587fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org        if (fProxy) {
58687fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org            size += fProxy->contextSize();
58787fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org        }
58887fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org        return size;
58987fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org    }
5908a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
591ce56d965069c1649afe14319cb239e6ad670682acommit-bot@chromium.org    virtual Context* onCreateContext(const ContextRec& rec, void* storage) const SK_OVERRIDE {
592ce56d965069c1649afe14319cb239e6ad670682acommit-bot@chromium.org        SkShader::Context* proxyContext = NULL;
593a641f3f18e5319773989812a888f3fad49e4f2adreed@google.com        if (fProxy) {
59487fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org            char* proxyContextStorage = (char*) storage + sizeof(Sk3DShaderContext);
595e901b6de3ef8dea842008a08fc81e92fb1478d61commit-bot@chromium.org            proxyContext = fProxy->createContext(rec, proxyContextStorage);
596ce56d965069c1649afe14319cb239e6ad670682acommit-bot@chromium.org            if (!proxyContext) {
597ce56d965069c1649afe14319cb239e6ad670682acommit-bot@chromium.org                return NULL;
598ce56d965069c1649afe14319cb239e6ad670682acommit-bot@chromium.org            }
599a641f3f18e5319773989812a888f3fad49e4f2adreed@google.com        }
600e901b6de3ef8dea842008a08fc81e92fb1478d61commit-bot@chromium.org        return SkNEW_PLACEMENT_ARGS(storage, Sk3DShaderContext, (*this, rec, proxyContext));
6018a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
60282065d667f64e232bcde2ad849756a6096fcbe6freed@google.com
60387fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org    class Sk3DShaderContext : public SkShader::Context {
60487fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org    public:
60587fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org        // Calls proxyContext's destructor but will NOT free its memory.
606e901b6de3ef8dea842008a08fc81e92fb1478d61commit-bot@chromium.org        Sk3DShaderContext(const Sk3DShader& shader, const ContextRec& rec,
607e901b6de3ef8dea842008a08fc81e92fb1478d61commit-bot@chromium.org                          SkShader::Context* proxyContext)
608e901b6de3ef8dea842008a08fc81e92fb1478d61commit-bot@chromium.org            : INHERITED(shader, rec)
60987fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org            , fMask(NULL)
61087fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org            , fProxyContext(proxyContext)
61187fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org        {
61287fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org            if (!fProxyContext) {
613e901b6de3ef8dea842008a08fc81e92fb1478d61commit-bot@chromium.org                fPMColor = SkPreMultiplyColor(rec.fPaint->getColor());
61487fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org            }
61582065d667f64e232bcde2ad849756a6096fcbe6freed@google.com        }
6168a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
61787fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org        virtual ~Sk3DShaderContext() {
61887fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org            if (fProxyContext) {
61987fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org                fProxyContext->~Context();
62082065d667f64e232bcde2ad849756a6096fcbe6freed@google.com            }
6218a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
6228a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
6239f23a27ed9961fd4575864e590eda328452895e7reed        virtual void set3DMask(const SkMask* mask) SK_OVERRIDE { fMask = mask; }
6248a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
62587fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org        virtual void shadeSpan(int x, int y, SkPMColor span[], int count) SK_OVERRIDE {
62687fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org            if (fProxyContext) {
62787fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org                fProxyContext->shadeSpan(x, y, span, count);
62887fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org            }
6298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
63087fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org            if (fMask == NULL) {
63187fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org                if (fProxyContext == NULL) {
63287fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org                    sk_memset32(span, fPMColor, count);
63387fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org                }
63487fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org                return;
63587fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org            }
6368a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
63787fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org            SkASSERT(fMask->fBounds.contains(x, y));
63887fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org            SkASSERT(fMask->fBounds.contains(x + count - 1, y));
63987fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org
64087fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org            size_t          size = fMask->computeImageSize();
64187fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org            const uint8_t*  alpha = fMask->getAddr8(x, y);
64287fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org            const uint8_t*  mulp = alpha + size;
64387fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org            const uint8_t*  addp = mulp + size;
64487fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org
64587fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org            if (fProxyContext) {
64687fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org                for (int i = 0; i < count; i++) {
64787fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org                    if (alpha[i]) {
64887fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org                        SkPMColor c = span[i];
64987fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org                        if (c) {
65087fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org                            unsigned a = SkGetPackedA32(c);
65187fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org                            unsigned r = SkGetPackedR32(c);
65287fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org                            unsigned g = SkGetPackedG32(c);
65387fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org                            unsigned b = SkGetPackedB32(c);
65487fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org
65587fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org                            unsigned mul = SkAlpha255To256(mulp[i]);
65687fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org                            unsigned add = addp[i];
65787fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org
65887fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org                            r = SkFastMin32(SkAlphaMul(r, mul) + add, a);
65987fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org                            g = SkFastMin32(SkAlphaMul(g, mul) + add, a);
66087fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org                            b = SkFastMin32(SkAlphaMul(b, mul) + add, a);
66187fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org
66287fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org                            span[i] = SkPackARGB32(a, r, g, b);
66387fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org                        }
66487fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org                    } else {
66587fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org                        span[i] = 0;
66687fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org                    }
66787fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org                }
66887fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org            } else {    // color
66987fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org                unsigned a = SkGetPackedA32(fPMColor);
67087fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org                unsigned r = SkGetPackedR32(fPMColor);
67187fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org                unsigned g = SkGetPackedG32(fPMColor);
67287fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org                unsigned b = SkGetPackedB32(fPMColor);
67387fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org                for (int i = 0; i < count; i++) {
67487fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org                    if (alpha[i]) {
6758a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                        unsigned mul = SkAlpha255To256(mulp[i]);
6768a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                        unsigned add = addp[i];
6778a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
67887fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org                        span[i] = SkPackARGB32( a,
67987fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org                                        SkFastMin32(SkAlphaMul(r, mul) + add, a),
68087fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org                                        SkFastMin32(SkAlphaMul(g, mul) + add, a),
68187fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org                                        SkFastMin32(SkAlphaMul(b, mul) + add, a));
68287fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org                    } else {
68387fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org                        span[i] = 0;
6848a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                    }
68582065d667f64e232bcde2ad849756a6096fcbe6freed@google.com                }
6868a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            }
6878a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
68887fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org
68987fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org    private:
69087fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org        // Unowned.
69187fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org        const SkMask*       fMask;
69287fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org        // Memory is unowned, but we need to call the destructor.
69387fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org        SkShader::Context*  fProxyContext;
69487fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org        SkPMColor           fPMColor;
69587fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org
69687fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org        typedef SkShader::Context INHERITED;
69787fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org    };
69882065d667f64e232bcde2ad849756a6096fcbe6freed@google.com
6990f10f7bf1fb43ca6346dc220a076773b1f19a367commit-bot@chromium.org#ifndef SK_IGNORE_TO_STRING
70076f9e938df0b5826fd4c80b854ceafaf385cfbe1robertphillips@google.com    virtual void toString(SkString* str) const SK_OVERRIDE {
70176f9e938df0b5826fd4c80b854ceafaf385cfbe1robertphillips@google.com        str->append("Sk3DShader: (");
70276f9e938df0b5826fd4c80b854ceafaf385cfbe1robertphillips@google.com
70376f9e938df0b5826fd4c80b854ceafaf385cfbe1robertphillips@google.com        if (NULL != fProxy) {
70476f9e938df0b5826fd4c80b854ceafaf385cfbe1robertphillips@google.com            str->append("Proxy: ");
70576f9e938df0b5826fd4c80b854ceafaf385cfbe1robertphillips@google.com            fProxy->toString(str);
70676f9e938df0b5826fd4c80b854ceafaf385cfbe1robertphillips@google.com        }
70776f9e938df0b5826fd4c80b854ceafaf385cfbe1robertphillips@google.com
70876f9e938df0b5826fd4c80b854ceafaf385cfbe1robertphillips@google.com        this->INHERITED::toString(str);
70976f9e938df0b5826fd4c80b854ceafaf385cfbe1robertphillips@google.com
71076f9e938df0b5826fd4c80b854ceafaf385cfbe1robertphillips@google.com        str->append(")");
71176f9e938df0b5826fd4c80b854ceafaf385cfbe1robertphillips@google.com    }
71276f9e938df0b5826fd4c80b854ceafaf385cfbe1robertphillips@google.com#endif
71376f9e938df0b5826fd4c80b854ceafaf385cfbe1robertphillips@google.com
714ba28d03e94dc221d6a803bf2a84a420b9159255cdjsollen@google.com    SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(Sk3DShader)
715ba28d03e94dc221d6a803bf2a84a420b9159255cdjsollen@google.com
7168a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comprotected:
7178b0e8ac5f582de80356019406e2975079bf0829dcommit-bot@chromium.org    Sk3DShader(SkReadBuffer& buffer) : INHERITED(buffer) {
718353482251e61971a8cf3a60bbb6910f482be634freed@google.com        fProxy = buffer.readShader();
71987fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org        // Leaving this here until we bump the picture version, though this
72087fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org        // shader should never be recorded.
72187fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org        buffer.readColor();
7228a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
72382065d667f64e232bcde2ad849756a6096fcbe6freed@google.com
7248b0e8ac5f582de80356019406e2975079bf0829dcommit-bot@chromium.org    virtual void flatten(SkWriteBuffer& buffer) const SK_OVERRIDE {
7258a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        this->INHERITED::flatten(buffer);
7268a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        buffer.writeFlattenable(fProxy);
72787fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org        // Leaving this here until we bump the picture version, though this
72887fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org        // shader should never be recorded.
72987fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org        buffer.writeColor(SkColor());
7308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
73182065d667f64e232bcde2ad849756a6096fcbe6freed@google.com
7328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comprivate:
7338a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkShader*       fProxy;
7348a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
7358a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    typedef SkShader INHERITED;
7368a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com};
7378a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
7388a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comclass Sk3DBlitter : public SkBlitter {
7398a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.compublic:
7409f23a27ed9961fd4575864e590eda328452895e7reed    Sk3DBlitter(SkBlitter* proxy, SkShader::Context* shaderContext)
741a5572e5bb2a2bbeeb59de0741c2527869d365a0ccommit-bot@chromium.org        : fProxy(proxy)
7429f23a27ed9961fd4575864e590eda328452895e7reed        , fShaderContext(shaderContext)
743a5572e5bb2a2bbeeb59de0741c2527869d365a0ccommit-bot@chromium.org    {}
7448a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
74582065d667f64e232bcde2ad849756a6096fcbe6freed@google.com    virtual void blitH(int x, int y, int width) {
7468a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        fProxy->blitH(x, y, width);
7478a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
74882065d667f64e232bcde2ad849756a6096fcbe6freed@google.com
74982065d667f64e232bcde2ad849756a6096fcbe6freed@google.com    virtual void blitAntiH(int x, int y, const SkAlpha antialias[],
75082065d667f64e232bcde2ad849756a6096fcbe6freed@google.com                           const int16_t runs[]) {
7518a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        fProxy->blitAntiH(x, y, antialias, runs);
7528a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
75382065d667f64e232bcde2ad849756a6096fcbe6freed@google.com
75482065d667f64e232bcde2ad849756a6096fcbe6freed@google.com    virtual void blitV(int x, int y, int height, SkAlpha alpha) {
7558a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        fProxy->blitV(x, y, height, alpha);
7568a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
75782065d667f64e232bcde2ad849756a6096fcbe6freed@google.com
75882065d667f64e232bcde2ad849756a6096fcbe6freed@google.com    virtual void blitRect(int x, int y, int width, int height) {
7598a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        fProxy->blitRect(x, y, width, height);
7608a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
76182065d667f64e232bcde2ad849756a6096fcbe6freed@google.com
76282065d667f64e232bcde2ad849756a6096fcbe6freed@google.com    virtual void blitMask(const SkMask& mask, const SkIRect& clip) {
76382065d667f64e232bcde2ad849756a6096fcbe6freed@google.com        if (mask.fFormat == SkMask::k3D_Format) {
7649f23a27ed9961fd4575864e590eda328452895e7reed            fShaderContext->set3DMask(&mask);
7658a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
7668a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            ((SkMask*)&mask)->fFormat = SkMask::kA8_Format;
7678a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            fProxy->blitMask(mask, clip);
7688a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            ((SkMask*)&mask)->fFormat = SkMask::k3D_Format;
7698a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
7709f23a27ed9961fd4575864e590eda328452895e7reed            fShaderContext->set3DMask(NULL);
77182065d667f64e232bcde2ad849756a6096fcbe6freed@google.com        } else {
7728a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            fProxy->blitMask(mask, clip);
77382065d667f64e232bcde2ad849756a6096fcbe6freed@google.com        }
7748a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
77582065d667f64e232bcde2ad849756a6096fcbe6freed@google.com
7768a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comprivate:
77787fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org    // Both pointers are unowned. They will be deleted by SkSmallAllocator.
7789f23a27ed9961fd4575864e590eda328452895e7reed    SkBlitter*          fProxy;
7799f23a27ed9961fd4575864e590eda328452895e7reed    SkShader::Context*  fShaderContext;
7808a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com};
7818a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
78282065d667f64e232bcde2ad849756a6096fcbe6freed@google.com///////////////////////////////////////////////////////////////////////////////
7838a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
7848a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkCoreBlitters.h"
7858a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
786d252db03d9650013b545ef9781fe993c07f8f314reed@android.comstatic bool just_solid_color(const SkPaint& paint) {
787d252db03d9650013b545ef9781fe993c07f8f314reed@android.com    if (paint.getAlpha() == 0xFF && paint.getColorFilter() == NULL) {
788d252db03d9650013b545ef9781fe993c07f8f314reed@android.com        SkShader* shader = paint.getShader();
78987fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org        if (NULL == shader) {
790d252db03d9650013b545ef9781fe993c07f8f314reed@android.com            return true;
791d252db03d9650013b545ef9781fe993c07f8f314reed@android.com        }
792d252db03d9650013b545ef9781fe993c07f8f314reed@android.com    }
793d252db03d9650013b545ef9781fe993c07f8f314reed@android.com    return false;
794d252db03d9650013b545ef9781fe993c07f8f314reed@android.com}
79582065d667f64e232bcde2ad849756a6096fcbe6freed@google.com
796d252db03d9650013b545ef9781fe993c07f8f314reed@android.com/** By analyzing the paint (with an xfermode), we may decide we can take
797d252db03d9650013b545ef9781fe993c07f8f314reed@android.com    special action. This enum lists our possible actions
798d252db03d9650013b545ef9781fe993c07f8f314reed@android.com */
799d252db03d9650013b545ef9781fe993c07f8f314reed@android.comenum XferInterp {
800d252db03d9650013b545ef9781fe993c07f8f314reed@android.com    kNormal_XferInterp,         // no special interpretation, draw normally
801d252db03d9650013b545ef9781fe993c07f8f314reed@android.com    kSrcOver_XferInterp,        // draw as if in srcover mode
802d252db03d9650013b545ef9781fe993c07f8f314reed@android.com    kSkipDrawing_XferInterp     // draw nothing
803d252db03d9650013b545ef9781fe993c07f8f314reed@android.com};
804d252db03d9650013b545ef9781fe993c07f8f314reed@android.com
805d252db03d9650013b545ef9781fe993c07f8f314reed@android.comstatic XferInterp interpret_xfermode(const SkPaint& paint, SkXfermode* xfer,
806900ecf2f1579d42c9d2959831787af0346320f86reed@google.com                                     SkColorType deviceCT) {
807845fdaca174f4675e9acc164b510e3a5ffa9053creed@android.com    SkXfermode::Mode  mode;
80882065d667f64e232bcde2ad849756a6096fcbe6freed@google.com
809be2aa2aa1f8bf73d974bdd9438fc741bbf0cfbe6mike@reedtribe.org    if (SkXfermode::AsMode(xfer, &mode)) {
810d252db03d9650013b545ef9781fe993c07f8f314reed@android.com        switch (mode) {
811845fdaca174f4675e9acc164b510e3a5ffa9053creed@android.com            case SkXfermode::kSrc_Mode:
812d252db03d9650013b545ef9781fe993c07f8f314reed@android.com                if (just_solid_color(paint)) {
813d252db03d9650013b545ef9781fe993c07f8f314reed@android.com                    return kSrcOver_XferInterp;
814d252db03d9650013b545ef9781fe993c07f8f314reed@android.com                }
815d252db03d9650013b545ef9781fe993c07f8f314reed@android.com                break;
816845fdaca174f4675e9acc164b510e3a5ffa9053creed@android.com            case SkXfermode::kDst_Mode:
817d252db03d9650013b545ef9781fe993c07f8f314reed@android.com                return kSkipDrawing_XferInterp;
818845fdaca174f4675e9acc164b510e3a5ffa9053creed@android.com            case SkXfermode::kSrcOver_Mode:
819d252db03d9650013b545ef9781fe993c07f8f314reed@android.com                return kSrcOver_XferInterp;
820845fdaca174f4675e9acc164b510e3a5ffa9053creed@android.com            case SkXfermode::kDstOver_Mode:
821900ecf2f1579d42c9d2959831787af0346320f86reed@google.com                if (kRGB_565_SkColorType == deviceCT) {
822d252db03d9650013b545ef9781fe993c07f8f314reed@android.com                    return kSkipDrawing_XferInterp;
823d252db03d9650013b545ef9781fe993c07f8f314reed@android.com                }
824d252db03d9650013b545ef9781fe993c07f8f314reed@android.com                break;
825845fdaca174f4675e9acc164b510e3a5ffa9053creed@android.com            case SkXfermode::kSrcIn_Mode:
826900ecf2f1579d42c9d2959831787af0346320f86reed@google.com                if (kRGB_565_SkColorType == deviceCT &&
827d252db03d9650013b545ef9781fe993c07f8f314reed@android.com                    just_solid_color(paint)) {
828d252db03d9650013b545ef9781fe993c07f8f314reed@android.com                    return kSrcOver_XferInterp;
829d252db03d9650013b545ef9781fe993c07f8f314reed@android.com                }
830d252db03d9650013b545ef9781fe993c07f8f314reed@android.com                break;
831845fdaca174f4675e9acc164b510e3a5ffa9053creed@android.com            case SkXfermode::kDstIn_Mode:
832d252db03d9650013b545ef9781fe993c07f8f314reed@android.com                if (just_solid_color(paint)) {
833d252db03d9650013b545ef9781fe993c07f8f314reed@android.com                    return kSkipDrawing_XferInterp;
834d252db03d9650013b545ef9781fe993c07f8f314reed@android.com                }
835d252db03d9650013b545ef9781fe993c07f8f314reed@android.com                break;
836d252db03d9650013b545ef9781fe993c07f8f314reed@android.com            default:
837d252db03d9650013b545ef9781fe993c07f8f314reed@android.com                break;
838d252db03d9650013b545ef9781fe993c07f8f314reed@android.com        }
839d252db03d9650013b545ef9781fe993c07f8f314reed@android.com    }
840d252db03d9650013b545ef9781fe993c07f8f314reed@android.com    return kNormal_XferInterp;
841d252db03d9650013b545ef9781fe993c07f8f314reed@android.com}
842d252db03d9650013b545ef9781fe993c07f8f314reed@android.com
8438a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comSkBlitter* SkBlitter::Choose(const SkBitmap& device,
8448a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                             const SkMatrix& matrix,
8456b7aee387d3b4b2df5894b51fa1c0baf649c6540reed@google.com                             const SkPaint& origPaint,
846a5572e5bb2a2bbeeb59de0741c2527869d365a0ccommit-bot@chromium.org                             SkTBlitterAllocator* allocator,
847126f7f5244502c0cbf1e5fec1d2ad7a0f2eb6c34reed@google.com                             bool drawCoverage) {
848a5572e5bb2a2bbeeb59de0741c2527869d365a0ccommit-bot@chromium.org    SkASSERT(allocator != NULL);
8498a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
8508a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkBlitter*  blitter = NULL;
8518a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
8528a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    // which check, in case we're being called by a client with a dummy device
8538a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    // (e.g. they have a bounder that always aborts the draw)
854900ecf2f1579d42c9d2959831787af0346320f86reed@google.com    if (kUnknown_SkColorType == device.colorType() ||
855900ecf2f1579d42c9d2959831787af0346320f86reed@google.com            (drawCoverage && (kAlpha_8_SkColorType != device.colorType()))) {
856a5572e5bb2a2bbeeb59de0741c2527869d365a0ccommit-bot@chromium.org        blitter = allocator->createT<SkNullBlitter>();
8578a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return blitter;
8588a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
8598a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
860458849004892c05fa1dcbcf6d355dfcce028d77areed@google.com    SkShader* shader = origPaint.getShader();
861458849004892c05fa1dcbcf6d355dfcce028d77areed@google.com    SkColorFilter* cf = origPaint.getColorFilter();
862458849004892c05fa1dcbcf6d355dfcce028d77areed@google.com    SkXfermode* mode = origPaint.getXfermode();
8638a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    Sk3DShader* shader3D = NULL;
864458849004892c05fa1dcbcf6d355dfcce028d77areed@google.com
8655dc26b97366934ba0f896cea02a3fec027d5d5c1bsalomon@google.com    SkTCopyOnFirstWrite<SkPaint> paint(origPaint);
866fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
867458849004892c05fa1dcbcf6d355dfcce028d77areed@google.com    if (origPaint.getMaskFilter() != NULL &&
868458849004892c05fa1dcbcf6d355dfcce028d77areed@google.com            origPaint.getMaskFilter()->getFormat() == SkMask::k3D_Format) {
8698a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        shader3D = SkNEW_ARGS(Sk3DShader, (shader));
870458849004892c05fa1dcbcf6d355dfcce028d77areed@google.com        // we know we haven't initialized lazyPaint yet, so just do it
8715dc26b97366934ba0f896cea02a3fec027d5d5c1bsalomon@google.com        paint.writable()->setShader(shader3D)->unref();
8728a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        shader = shader3D;
8738a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
8748a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
875d252db03d9650013b545ef9781fe993c07f8f314reed@android.com    if (NULL != mode) {
876900ecf2f1579d42c9d2959831787af0346320f86reed@google.com        switch (interpret_xfermode(*paint, mode, device.colorType())) {
877d252db03d9650013b545ef9781fe993c07f8f314reed@android.com            case kSrcOver_XferInterp:
878d252db03d9650013b545ef9781fe993c07f8f314reed@android.com                mode = NULL;
8795dc26b97366934ba0f896cea02a3fec027d5d5c1bsalomon@google.com                paint.writable()->setXfermode(NULL);
880d252db03d9650013b545ef9781fe993c07f8f314reed@android.com                break;
881a5572e5bb2a2bbeeb59de0741c2527869d365a0ccommit-bot@chromium.org            case kSkipDrawing_XferInterp:{
882a5572e5bb2a2bbeeb59de0741c2527869d365a0ccommit-bot@chromium.org                blitter = allocator->createT<SkNullBlitter>();
883d252db03d9650013b545ef9781fe993c07f8f314reed@android.com                return blitter;
884a5572e5bb2a2bbeeb59de0741c2527869d365a0ccommit-bot@chromium.org            }
885d252db03d9650013b545ef9781fe993c07f8f314reed@android.com            default:
886d252db03d9650013b545ef9781fe993c07f8f314reed@android.com                break;
887d252db03d9650013b545ef9781fe993c07f8f314reed@android.com        }
888d252db03d9650013b545ef9781fe993c07f8f314reed@android.com    }
889d252db03d9650013b545ef9781fe993c07f8f314reed@android.com
89013201e74f43b9c5fa173339eb36de515370e6973reed@google.com    /*
89113201e74f43b9c5fa173339eb36de515370e6973reed@google.com     *  If the xfermode is CLEAR, then we can completely ignore the installed
89213201e74f43b9c5fa173339eb36de515370e6973reed@google.com     *  color/shader/colorfilter, and just pretend we're SRC + color==0. This
89313201e74f43b9c5fa173339eb36de515370e6973reed@google.com     *  will fall into our optimizations for SRC mode.
89413201e74f43b9c5fa173339eb36de515370e6973reed@google.com     */
89513201e74f43b9c5fa173339eb36de515370e6973reed@google.com    if (SkXfermode::IsMode(mode, SkXfermode::kClear_Mode)) {
89613201e74f43b9c5fa173339eb36de515370e6973reed@google.com        SkPaint* p = paint.writable();
89713201e74f43b9c5fa173339eb36de515370e6973reed@google.com        shader = p->setShader(NULL);
89813201e74f43b9c5fa173339eb36de515370e6973reed@google.com        cf = p->setColorFilter(NULL);
89913201e74f43b9c5fa173339eb36de515370e6973reed@google.com        mode = p->setXfermodeMode(SkXfermode::kSrc_Mode);
90013201e74f43b9c5fa173339eb36de515370e6973reed@google.com        p->setColor(0);
90113201e74f43b9c5fa173339eb36de515370e6973reed@google.com    }
90213201e74f43b9c5fa173339eb36de515370e6973reed@google.com
9036b7aee387d3b4b2df5894b51fa1c0baf649c6540reed@google.com    if (NULL == shader) {
9046b7aee387d3b4b2df5894b51fa1c0baf649c6540reed@google.com        if (mode) {
9056b7aee387d3b4b2df5894b51fa1c0baf649c6540reed@google.com            // xfermodes (and filters) require shaders for our current blitters
90676a3b2abd02841c4ae786ac4cf59c3a51c545f73commit-bot@chromium.org            shader = SkNEW_ARGS(SkColorShader, (paint->getColor()));
9075dc26b97366934ba0f896cea02a3fec027d5d5c1bsalomon@google.com            paint.writable()->setShader(shader)->unref();
90876a3b2abd02841c4ae786ac4cf59c3a51c545f73commit-bot@chromium.org            paint.writable()->setAlpha(0xFF);
9096b7aee387d3b4b2df5894b51fa1c0baf649c6540reed@google.com        } else if (cf) {
9106b7aee387d3b4b2df5894b51fa1c0baf649c6540reed@google.com            // if no shader && no xfermode, we just apply the colorfilter to
9116b7aee387d3b4b2df5894b51fa1c0baf649c6540reed@google.com            // our color and move on.
9125dc26b97366934ba0f896cea02a3fec027d5d5c1bsalomon@google.com            SkPaint* writablePaint = paint.writable();
9135dc26b97366934ba0f896cea02a3fec027d5d5c1bsalomon@google.com            writablePaint->setColor(cf->filterColor(paint->getColor()));
9145dc26b97366934ba0f896cea02a3fec027d5d5c1bsalomon@google.com            writablePaint->setColorFilter(NULL);
9156b7aee387d3b4b2df5894b51fa1c0baf649c6540reed@google.com            cf = NULL;
9166b7aee387d3b4b2df5894b51fa1c0baf649c6540reed@google.com        }
9178a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
91882065d667f64e232bcde2ad849756a6096fcbe6freed@google.com
9196b7aee387d3b4b2df5894b51fa1c0baf649c6540reed@google.com    if (cf) {
9208a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkASSERT(shader);
9216b7aee387d3b4b2df5894b51fa1c0baf649c6540reed@google.com        shader = SkNEW_ARGS(SkFilterShader, (shader, cf));
9225dc26b97366934ba0f896cea02a3fec027d5d5c1bsalomon@google.com        paint.writable()->setShader(shader)->unref();
9231fc4c605def61d9e10489f9cd63dc378baa6ade3reed@android.com        // blitters should ignore the presence/absence of a filter, since
9241fc4c605def61d9e10489f9cd63dc378baa6ade3reed@android.com        // if there is one, the shader will take care of it.
9258a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
92682065d667f64e232bcde2ad849756a6096fcbe6freed@google.com
927a641f3f18e5319773989812a888f3fad49e4f2adreed@google.com    /*
92887fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org     *  We create a SkShader::Context object, and store it on the blitter.
929a641f3f18e5319773989812a888f3fad49e4f2adreed@google.com     */
93087fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org    SkShader::Context* shaderContext;
93187fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org    if (shader) {
932e901b6de3ef8dea842008a08fc81e92fb1478d61commit-bot@chromium.org        SkShader::ContextRec rec(device, *paint, matrix);
93387fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org        // Try to create the ShaderContext
93487fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org        void* storage = allocator->reserveT<SkShader::Context>(shader->contextSize());
935e901b6de3ef8dea842008a08fc81e92fb1478d61commit-bot@chromium.org        shaderContext = shader->createContext(rec, storage);
93687fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org        if (!shaderContext) {
93787fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org            allocator->freeLast();
93887fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org            blitter = allocator->createT<SkNullBlitter>();
93987fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org            return blitter;
94087fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org        }
94187fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org        SkASSERT(shaderContext);
94287fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org        SkASSERT((void*) shaderContext == storage);
94387fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org    } else {
94487fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org        shaderContext = NULL;
9458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
9468a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
947ab7442c8d733e0642d1cd80af23cdab43d77039eskia.committer@gmail.com
948900ecf2f1579d42c9d2959831787af0346320f86reed@google.com    switch (device.colorType()) {
949900ecf2f1579d42c9d2959831787af0346320f86reed@google.com        case kAlpha_8_SkColorType:
950126f7f5244502c0cbf1e5fec1d2ad7a0f2eb6c34reed@google.com            if (drawCoverage) {
951126f7f5244502c0cbf1e5fec1d2ad7a0f2eb6c34reed@google.com                SkASSERT(NULL == shader);
952126f7f5244502c0cbf1e5fec1d2ad7a0f2eb6c34reed@google.com                SkASSERT(NULL == paint->getXfermode());
953a5572e5bb2a2bbeeb59de0741c2527869d365a0ccommit-bot@chromium.org                blitter = allocator->createT<SkA8_Coverage_Blitter>(device, *paint);
954126f7f5244502c0cbf1e5fec1d2ad7a0f2eb6c34reed@google.com            } else if (shader) {
95587fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org                blitter = allocator->createT<SkA8_Shader_Blitter>(device, *paint, shaderContext);
95682065d667f64e232bcde2ad849756a6096fcbe6freed@google.com            } else {
957a5572e5bb2a2bbeeb59de0741c2527869d365a0ccommit-bot@chromium.org                blitter = allocator->createT<SkA8_Blitter>(device, *paint);
95882065d667f64e232bcde2ad849756a6096fcbe6freed@google.com            }
95982065d667f64e232bcde2ad849756a6096fcbe6freed@google.com            break;
96082065d667f64e232bcde2ad849756a6096fcbe6freed@google.com
961900ecf2f1579d42c9d2959831787af0346320f86reed@google.com        case kRGB_565_SkColorType:
96287fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org            blitter = SkBlitter_ChooseD565(device, *paint, shaderContext, allocator);
96382065d667f64e232bcde2ad849756a6096fcbe6freed@google.com            break;
96482065d667f64e232bcde2ad849756a6096fcbe6freed@google.com
96528fcae2ec77eb16a79e155f8d788b20457f1c951commit-bot@chromium.org        case kN32_SkColorType:
96682065d667f64e232bcde2ad849756a6096fcbe6freed@google.com            if (shader) {
96787fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org                blitter = allocator->createT<SkARGB32_Shader_Blitter>(
96887fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org                        device, *paint, shaderContext);
969458849004892c05fa1dcbcf6d355dfcce028d77areed@google.com            } else if (paint->getColor() == SK_ColorBLACK) {
970a5572e5bb2a2bbeeb59de0741c2527869d365a0ccommit-bot@chromium.org                blitter = allocator->createT<SkARGB32_Black_Blitter>(device, *paint);
971458849004892c05fa1dcbcf6d355dfcce028d77areed@google.com            } else if (paint->getAlpha() == 0xFF) {
972a5572e5bb2a2bbeeb59de0741c2527869d365a0ccommit-bot@chromium.org                blitter = allocator->createT<SkARGB32_Opaque_Blitter>(device, *paint);
97382065d667f64e232bcde2ad849756a6096fcbe6freed@google.com            } else {
974a5572e5bb2a2bbeeb59de0741c2527869d365a0ccommit-bot@chromium.org                blitter = allocator->createT<SkARGB32_Blitter>(device, *paint);
97582065d667f64e232bcde2ad849756a6096fcbe6freed@google.com            }
97682065d667f64e232bcde2ad849756a6096fcbe6freed@google.com            break;
97782065d667f64e232bcde2ad849756a6096fcbe6freed@google.com
97882065d667f64e232bcde2ad849756a6096fcbe6freed@google.com        default:
9790c00f21fee3f5cfa3aa7e5d46ff94cb8cf340451tomhudson@google.com            SkDEBUGFAIL("unsupported device config");
980a5572e5bb2a2bbeeb59de0741c2527869d365a0ccommit-bot@chromium.org            blitter = allocator->createT<SkNullBlitter>();
98182065d667f64e232bcde2ad849756a6096fcbe6freed@google.com            break;
9828a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
9838a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
98482065d667f64e232bcde2ad849756a6096fcbe6freed@google.com    if (shader3D) {
985a5572e5bb2a2bbeeb59de0741c2527869d365a0ccommit-bot@chromium.org        SkBlitter* innerBlitter = blitter;
986a5572e5bb2a2bbeeb59de0741c2527869d365a0ccommit-bot@chromium.org        // innerBlitter was allocated by allocator, which will delete it.
9879f23a27ed9961fd4575864e590eda328452895e7reed        // We know shaderContext or its proxies is of type Sk3DShaderContext, so we need to
9889f23a27ed9961fd4575864e590eda328452895e7reed        // wrapper the blitter to notify it when we see an emboss mask.
9899f23a27ed9961fd4575864e590eda328452895e7reed        blitter = allocator->createT<Sk3DBlitter>(innerBlitter, shaderContext);
9908a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
9918a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return blitter;
9928a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
9938a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
99482065d667f64e232bcde2ad849756a6096fcbe6freed@google.com///////////////////////////////////////////////////////////////////////////////
9958a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
996ce56d965069c1649afe14319cb239e6ad670682acommit-bot@chromium.orgclass SkTransparentShaderContext : public SkShader::Context {
997ce56d965069c1649afe14319cb239e6ad670682acommit-bot@chromium.orgpublic:
998ce56d965069c1649afe14319cb239e6ad670682acommit-bot@chromium.org    SkTransparentShaderContext(const SkShader& shader, const SkShader::ContextRec& rec)
999ca76c55d60dfe041e30e210d41fa0feb7fb54a1fscroggo        // Override rec with the identity matrix, so it is guaranteed to be invertible.
1000ca76c55d60dfe041e30e210d41fa0feb7fb54a1fscroggo        : INHERITED(shader, SkShader::ContextRec(*rec.fDevice, *rec.fPaint, SkMatrix::I())) {}
1001ce56d965069c1649afe14319cb239e6ad670682acommit-bot@chromium.org
1002ce56d965069c1649afe14319cb239e6ad670682acommit-bot@chromium.org    virtual void shadeSpan(int x, int y, SkPMColor colors[], int count) SK_OVERRIDE {
1003ce56d965069c1649afe14319cb239e6ad670682acommit-bot@chromium.org        sk_bzero(colors, count * sizeof(SkPMColor));
1004ce56d965069c1649afe14319cb239e6ad670682acommit-bot@chromium.org    }
1005ce56d965069c1649afe14319cb239e6ad670682acommit-bot@chromium.org
1006ce56d965069c1649afe14319cb239e6ad670682acommit-bot@chromium.orgprivate:
1007ce56d965069c1649afe14319cb239e6ad670682acommit-bot@chromium.org    typedef SkShader::Context INHERITED;
1008ce56d965069c1649afe14319cb239e6ad670682acommit-bot@chromium.org};
1009ce56d965069c1649afe14319cb239e6ad670682acommit-bot@chromium.org
101087fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.orgSkShaderBlitter::SkShaderBlitter(const SkBitmap& device, const SkPaint& paint,
101187fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org                                 SkShader::Context* shaderContext)
101287fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org        : INHERITED(device)
101387fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org        , fShader(paint.getShader())
101487fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org        , fShaderContext(shaderContext) {
10158a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkASSERT(fShader);
101687fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org    SkASSERT(fShaderContext);
10178a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
10188a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fShader->ref();
101987fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org    fShaderFlags = fShaderContext->getFlags();
10208a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
10218a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
10225119bdb952025a30f115b9c6a187173956e55097reed@android.comSkShaderBlitter::~SkShaderBlitter() {
10238a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fShader->unref();
10248a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
102587fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org
102680116dcf1e1baf9817ae42d0aca51f7eabaa2880commit-bot@chromium.orgbool SkShaderBlitter::resetShaderContext(const SkShader::ContextRec& rec) {
102787fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org    // Only destroy the old context if we have a new one. We need to ensure to have a
102887fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org    // live context in fShaderContext because the storage is owned by an SkSmallAllocator
102987fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org    // outside of this class.
103087fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org    // The new context will be of the same size as the old one because we use the same
103187fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org    // shader to create it. It is therefore safe to re-use the storage.
103287fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org    fShaderContext->~Context();
1033ce56d965069c1649afe14319cb239e6ad670682acommit-bot@chromium.org    SkShader::Context* ctx = fShader->createContext(rec, (void*)fShaderContext);
1034ce56d965069c1649afe14319cb239e6ad670682acommit-bot@chromium.org    if (NULL == ctx) {
1035ce56d965069c1649afe14319cb239e6ad670682acommit-bot@chromium.org        // Need a valid context in fShaderContext's storage, so we can later (or our caller) call
1036ce56d965069c1649afe14319cb239e6ad670682acommit-bot@chromium.org        // the in-place destructor.
1037ce56d965069c1649afe14319cb239e6ad670682acommit-bot@chromium.org        SkNEW_PLACEMENT_ARGS(fShaderContext, SkTransparentShaderContext, (*fShader, rec));
103880116dcf1e1baf9817ae42d0aca51f7eabaa2880commit-bot@chromium.org        return false;
1039ce56d965069c1649afe14319cb239e6ad670682acommit-bot@chromium.org    }
104080116dcf1e1baf9817ae42d0aca51f7eabaa2880commit-bot@chromium.org    return true;
104187fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org}
1042