1845fdaca174f4675e9acc164b510e3a5ffa9053creed@android.com/*
2ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * Copyright 2006 The Android Open Source Project
3845fdaca174f4675e9acc164b510e3a5ffa9053creed@android.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.
6845fdaca174f4675e9acc164b510e3a5ffa9053creed@android.com */
78a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
8c4cae85752e3e486cf4eac8cd8128f57b6f40563reed@android.com#include "SkBlitRow.h"
9e902f8dc7e111ede8b22cbd9bb74f326b0ce36fbMike Klein#include "SkBlendModePriv.h"
108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkColorFilter.h"
118a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkColorPriv.h"
12ac04fef619ad3939a25e66bdaef6f6b1e7f5ca50Herb Derby#include "SkArenaAlloc.h"
13db873d8677a2d4ecfe38a794a5d868301bdeeabereed#include "SkModeColorFilter.h"
14744908e5e81f81f34288a1b5547aa4ea990ad13dMike Klein#include "SkPM4fPriv.h"
1596b333a9a1b6a367d6c542118638e3108d8ed23bMike Klein#include "SkRasterPipeline.h"
168b0e8ac5f582de80356019406e2975079bf0829dcommit-bot@chromium.org#include "SkReadBuffer.h"
178b0e8ac5f582de80356019406e2975079bf0829dcommit-bot@chromium.org#include "SkWriteBuffer.h"
188a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkUtils.h"
196f6961ebad65c582318564b3688e78e5c99f3935Hal Canary#include "SkRandom.h"
201202c2ac563cdeb07406872825706b83e335c977robertphillips@google.com#include "SkString.h"
21c0b7e10c6a68f59e1653e6c18e6bc954b3c3f0cfcommit-bot@chromium.org#include "SkValidationUtils.h"
22dd9ffea9ce051a49dbc6544e6aa3cb68fe987f47reed#include "SkPM4f.h"
2331b3044af4e97c662076147d119ba233a163b769reed@google.com
24c7141eb8fba41f1e098499ef17d0bc79641d54c5reed//////////////////////////////////////////////////////////////////////////////////////////////////
25c7141eb8fba41f1e098499ef17d0bc79641d54c5reed
26c7141eb8fba41f1e098499ef17d0bc79641d54c5reed#ifndef SK_IGNORE_TO_STRING
27c7141eb8fba41f1e098499ef17d0bc79641d54c5reedvoid SkModeColorFilter::toString(SkString* str) const {
28c7141eb8fba41f1e098499ef17d0bc79641d54c5reed    str->append("SkModeColorFilter: color: 0x");
29c7141eb8fba41f1e098499ef17d0bc79641d54c5reed    str->appendHex(fColor);
30c7141eb8fba41f1e098499ef17d0bc79641d54c5reed    str->append(" mode: ");
31c7141eb8fba41f1e098499ef17d0bc79641d54c5reed    str->append(SkXfermode::ModeName(fMode));
32c7141eb8fba41f1e098499ef17d0bc79641d54c5reed}
33c7141eb8fba41f1e098499ef17d0bc79641d54c5reed#endif
34c7141eb8fba41f1e098499ef17d0bc79641d54c5reed
35faba3715b8ddfaa0ce4df79bc8006e9bc7694e5bMike Reedbool SkModeColorFilter::asColorMode(SkColor* color, SkBlendMode* mode) const {
36db873d8677a2d4ecfe38a794a5d868301bdeeabereed    if (color) {
37db873d8677a2d4ecfe38a794a5d868301bdeeabereed        *color = fColor;
388b0d0f6a9c01f45cd5bacf7aea2a32306fb16684reed@google.com    }
39db873d8677a2d4ecfe38a794a5d868301bdeeabereed    if (mode) {
40faba3715b8ddfaa0ce4df79bc8006e9bc7694e5bMike Reed        *mode = fMode;
411202c2ac563cdeb07406872825706b83e335c977robertphillips@google.com    }
42db873d8677a2d4ecfe38a794a5d868301bdeeabereed    return true;
43db873d8677a2d4ecfe38a794a5d868301bdeeabereed}
441202c2ac563cdeb07406872825706b83e335c977robertphillips@google.com
45db873d8677a2d4ecfe38a794a5d868301bdeeabereeduint32_t SkModeColorFilter::getFlags() const {
46c5b1228141bd26d4573552a00ebeb0b85a4768dfreed    uint32_t flags = 0;
4762a320c8d444cd04e4f2952c269ea4cbd58dee64reed    switch (fMode) {
487d954ad797176afedb9262fdea4507d0fc60eb9dMike Reed        case SkBlendMode::kDst:      //!< [Da, Dc]
497d954ad797176afedb9262fdea4507d0fc60eb9dMike Reed        case SkBlendMode::kSrcATop:  //!< [Da, Sc * Da + (1 - Sa) * Dc]
503125565804054691b110b4731bc5a32070fab780reed            flags |= kAlphaUnchanged_Flag;
5162a320c8d444cd04e4f2952c269ea4cbd58dee64reed        default:
5262a320c8d444cd04e4f2952c269ea4cbd58dee64reed            break;
5362a320c8d444cd04e4f2952c269ea4cbd58dee64reed    }
543125565804054691b110b4731bc5a32070fab780reed    return flags;
55db873d8677a2d4ecfe38a794a5d868301bdeeabereed}
5643c50c8c77df82c5cffb55cae2d386e59802b88freed@google.com
57db873d8677a2d4ecfe38a794a5d868301bdeeabereedvoid SkModeColorFilter::filterSpan(const SkPMColor shader[], int count, SkPMColor result[]) const {
58db873d8677a2d4ecfe38a794a5d868301bdeeabereed    SkPMColor       color = fPMColor;
59db873d8677a2d4ecfe38a794a5d868301bdeeabereed    SkXfermodeProc  proc = fProc;
609d524f22bfde5dc3dc8f48e1be39bdebd3bb0304halcanary
613125565804054691b110b4731bc5a32070fab780reed    for (int i = 0; i < count; i++) {
623125565804054691b110b4731bc5a32070fab780reed        result[i] = proc(color, shader[i]);
633125565804054691b110b4731bc5a32070fab780reed    }
643125565804054691b110b4731bc5a32070fab780reed}
6595cc012ccaea20f372893ae277ea0a8a6339d094mtklein
663125565804054691b110b4731bc5a32070fab780reedvoid SkModeColorFilter::filterSpan4f(const SkPM4f shader[], int count, SkPM4f result[]) const {
676a01554e9e8687c56e6b6707e0c6a02062a1824eMike Reed    SkXfermodeProc4f  proc = SkXfermode::GetProc4f(fMode);
68744908e5e81f81f34288a1b5547aa4ea990ad13dMike Klein    auto pm4f = SkColor4f::FromColor(fColor).premul();
69db873d8677a2d4ecfe38a794a5d868301bdeeabereed    for (int i = 0; i < count; i++) {
70744908e5e81f81f34288a1b5547aa4ea990ad13dMike Klein        result[i] = proc(pm4f, shader[i]);
718a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
72db873d8677a2d4ecfe38a794a5d868301bdeeabereed}
731447c6f7f4579942b32af6ffff1eadede40b42bctomhudson@google.com
74db873d8677a2d4ecfe38a794a5d868301bdeeabereedvoid SkModeColorFilter::flatten(SkWriteBuffer& buffer) const {
75db873d8677a2d4ecfe38a794a5d868301bdeeabereed    buffer.writeColor(fColor);
767d954ad797176afedb9262fdea4507d0fc60eb9dMike Reed    buffer.writeUInt((int)fMode);
77db873d8677a2d4ecfe38a794a5d868301bdeeabereed}
78fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
79db873d8677a2d4ecfe38a794a5d868301bdeeabereedvoid SkModeColorFilter::updateCache() {
80db873d8677a2d4ecfe38a794a5d868301bdeeabereed    fPMColor = SkPreMultiplyColor(fColor);
816a01554e9e8687c56e6b6707e0c6a02062a1824eMike Reed    fProc = SkXfermode::GetProc(fMode);
82db873d8677a2d4ecfe38a794a5d868301bdeeabereed}
838a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
8460c9b58b3214b0154c931656e91e39b230e987d8reedsk_sp<SkFlattenable> SkModeColorFilter::CreateProc(SkReadBuffer& buffer) {
859fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed    SkColor color = buffer.readColor();
867d954ad797176afedb9262fdea4507d0fc60eb9dMike Reed    SkBlendMode mode = (SkBlendMode)buffer.readUInt();
8760c9b58b3214b0154c931656e91e39b230e987d8reed    return SkColorFilter::MakeModeFilter(color, mode);
889fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed}
899fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed
90744908e5e81f81f34288a1b5547aa4ea990ad13dMike Kleinbool SkModeColorFilter::onAppendStages(SkRasterPipeline* p,
91744908e5e81f81f34288a1b5547aa4ea990ad13dMike Klein                                       SkColorSpace* dst,
92ac04fef619ad3939a25e66bdaef6f6b1e7f5ca50Herb Derby                                       SkArenaAlloc* scratch,
93744908e5e81f81f34288a1b5547aa4ea990ad13dMike Klein                                       bool shaderIsOpaque) const {
94526525a37c2550ab4292a02a179ed5d5fe291919Mike Klein    auto color = scratch->make<SkPM4f>(SkPM4f_from_SkColor(fColor, dst));
95744908e5e81f81f34288a1b5547aa4ea990ad13dMike Klein
96c5093411071222c752334dc6e38887020e986cc3Mike Klein    p->append(SkRasterPipeline::move_src_dst);
97744908e5e81f81f34288a1b5547aa4ea990ad13dMike Klein    p->append(SkRasterPipeline::constant_color, color);
98130863ef51a2a94e5bdf87f344c0e892b2403985Mike Klein    auto mode = (SkBlendMode)fMode;
99130863ef51a2a94e5bdf87f344c0e892b2403985Mike Klein    if (!SkBlendMode_AppendStages(mode, p)) {
100130863ef51a2a94e5bdf87f344c0e892b2403985Mike Klein        return false;
101130863ef51a2a94e5bdf87f344c0e892b2403985Mike Klein    }
102eea7c16d59a163bd5b858891bc916c49063ed8acMike Klein    if (SkBlendMode_CanOverflow(mode)) { p->append(SkRasterPipeline::clamp_a); }
103130863ef51a2a94e5bdf87f344c0e892b2403985Mike Klein    return true;
10496b333a9a1b6a367d6c542118638e3108d8ed23bMike Klein}
10596b333a9a1b6a367d6c542118638e3108d8ed23bMike Klein
106a34995e18b1f0a7d8c9f23451718bb30ff0105b0commit-bot@chromium.org///////////////////////////////////////////////////////////////////////////////
107a34995e18b1f0a7d8c9f23451718bb30ff0105b0commit-bot@chromium.org#if SK_SUPPORT_GPU
108a34995e18b1f0a7d8c9f23451718bb30ff0105b0commit-bot@chromium.org#include "GrBlend.h"
109ae4738f677c70f4ec7687422e1510ee3d80d810ebsalomon#include "effects/GrXfermodeFragmentProcessor.h"
110ae4738f677c70f4ec7687422e1510ee3d80d810ebsalomon#include "effects/GrConstColorProcessor.h"
111eb2a6761654307e8aeeeaabdd63c6bf9ab0411e9joshualitt#include "SkGr.h"
112a34995e18b1f0a7d8c9f23451718bb30ff0105b0commit-bot@chromium.org
113618d304eb394d64779be0ecdc5eff898242faa8fBrian Osmansk_sp<GrFragmentProcessor> SkModeColorFilter::asFragmentProcessor(
114618d304eb394d64779be0ecdc5eff898242faa8fBrian Osman                                                    GrContext*, SkColorSpace* dstColorSpace) const {
1157d954ad797176afedb9262fdea4507d0fc60eb9dMike Reed    if (SkBlendMode::kDst == fMode) {
116e25eea4b36a488448fb730f4e3dc5a900b0e2892bsalomon        return nullptr;
117e25eea4b36a488448fb730f4e3dc5a900b0e2892bsalomon    }
118e25eea4b36a488448fb730f4e3dc5a900b0e2892bsalomon
11906ca8ec87cf6fab57cadd043a5ac18c4154a4129bungeman    sk_sp<GrFragmentProcessor> constFP(
120618d304eb394d64779be0ecdc5eff898242faa8fBrian Osman        GrConstColorProcessor::Make(SkColorToPremulGrColor4f(fColor, dstColorSpace),
12106ca8ec87cf6fab57cadd043a5ac18c4154a4129bungeman                                    GrConstColorProcessor::kIgnore_InputMode));
12206ca8ec87cf6fab57cadd043a5ac18c4154a4129bungeman    sk_sp<GrFragmentProcessor> fp(
12306ca8ec87cf6fab57cadd043a5ac18c4154a4129bungeman        GrXfermodeFragmentProcessor::MakeFromSrcProcessor(std::move(constFP), fMode));
124e25eea4b36a488448fb730f4e3dc5a900b0e2892bsalomon    if (!fp) {
125e25eea4b36a488448fb730f4e3dc5a900b0e2892bsalomon        return nullptr;
126e25eea4b36a488448fb730f4e3dc5a900b0e2892bsalomon    }
127ae4738f677c70f4ec7687422e1510ee3d80d810ebsalomon#ifdef SK_DEBUG
128e25eea4b36a488448fb730f4e3dc5a900b0e2892bsalomon    // With a solid color input this should always be able to compute the blended color
129e25eea4b36a488448fb730f4e3dc5a900b0e2892bsalomon    // (at least for coeff modes)
1307d954ad797176afedb9262fdea4507d0fc60eb9dMike Reed    if ((unsigned)fMode <= (unsigned)SkBlendMode::kLastCoeffMode) {
131cb30bb2cb727e276792812c6390547dba474c831Brian Salomon        SkASSERT(fp->hasConstantOutputForConstantInput());
132a34995e18b1f0a7d8c9f23451718bb30ff0105b0commit-bot@chromium.org    }
133e25eea4b36a488448fb730f4e3dc5a900b0e2892bsalomon#endif
134e25eea4b36a488448fb730f4e3dc5a900b0e2892bsalomon    return fp;
135a34995e18b1f0a7d8c9f23451718bb30ff0105b0commit-bot@chromium.org}
136a34995e18b1f0a7d8c9f23451718bb30ff0105b0commit-bot@chromium.org
137a34995e18b1f0a7d8c9f23451718bb30ff0105b0commit-bot@chromium.org#endif
138a34995e18b1f0a7d8c9f23451718bb30ff0105b0commit-bot@chromium.org
139a34995e18b1f0a7d8c9f23451718bb30ff0105b0commit-bot@chromium.org///////////////////////////////////////////////////////////////////////////////
140a34995e18b1f0a7d8c9f23451718bb30ff0105b0commit-bot@chromium.org
141c7141eb8fba41f1e098499ef17d0bc79641d54c5reedclass Src_SkModeColorFilter final : public SkModeColorFilter {
1428a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.compublic:
1437d954ad797176afedb9262fdea4507d0fc60eb9dMike Reed    Src_SkModeColorFilter(SkColor color) : INHERITED(color, SkBlendMode::kSrc) {}
1448a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
14536352bf5e38f45a70ee4f4fc132a38048d38206dmtklein    void filterSpan(const SkPMColor shader[], int count, SkPMColor result[]) const override {
1468b0d0f6a9c01f45cd5bacf7aea2a32306fb16684reed@google.com        sk_memset32(result, this->getPMColor(), count);
1478a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
1488a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1491447c6f7f4579942b32af6ffff1eadede40b42bctomhudson@google.comprivate:
15043c50c8c77df82c5cffb55cae2d386e59802b88freed@google.com    typedef SkModeColorFilter INHERITED;
1518a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com};
1528a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
153c7141eb8fba41f1e098499ef17d0bc79641d54c5reedclass SrcOver_SkModeColorFilter final : public SkModeColorFilter {
1548a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.compublic:
1557d954ad797176afedb9262fdea4507d0fc60eb9dMike Reed    SrcOver_SkModeColorFilter(SkColor color) : INHERITED(color, SkBlendMode::kSrcOver) { }
1568a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
15736352bf5e38f45a70ee4f4fc132a38048d38206dmtklein    void filterSpan(const SkPMColor shader[], int count, SkPMColor result[]) const override {
15895cc012ccaea20f372893ae277ea0a8a6339d094mtklein        SkBlitRow::Color32(result, shader, count, this->getPMColor());
1598a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
1608a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1618a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comprivate:
16243c50c8c77df82c5cffb55cae2d386e59802b88freed@google.com    typedef SkModeColorFilter INHERITED;
1638a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com};
1648a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
16543c50c8c77df82c5cffb55cae2d386e59802b88freed@google.com///////////////////////////////////////////////////////////////////////////////
1668a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1677d954ad797176afedb9262fdea4507d0fc60eb9dMike Reedsk_sp<SkColorFilter> SkColorFilter::MakeModeFilter(SkColor color, SkBlendMode mode) {
1689fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed    if (!SkIsValidMode(mode)) {
16996fcdcc219d2a0d3579719b84b28bede76efba64halcanary        return nullptr;
1709fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed    }
1719fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed
1728a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    unsigned alpha = SkColorGetA(color);
1738a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1748a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    // first collaps some modes if possible
1758a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1767d954ad797176afedb9262fdea4507d0fc60eb9dMike Reed    if (SkBlendMode::kClear == mode) {
1778a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        color = 0;
1787d954ad797176afedb9262fdea4507d0fc60eb9dMike Reed        mode = SkBlendMode::kSrc;
1797d954ad797176afedb9262fdea4507d0fc60eb9dMike Reed    } else if (SkBlendMode::kSrcOver == mode) {
180845fdaca174f4675e9acc164b510e3a5ffa9053creed@android.com        if (0 == alpha) {
1817d954ad797176afedb9262fdea4507d0fc60eb9dMike Reed            mode = SkBlendMode::kDst;
182845fdaca174f4675e9acc164b510e3a5ffa9053creed@android.com        } else if (255 == alpha) {
1837d954ad797176afedb9262fdea4507d0fc60eb9dMike Reed            mode = SkBlendMode::kSrc;
1848a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
1858a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        // else just stay srcover
1868a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
1878a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1888a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    // weed out combinations that are noops, and just return null
1897d954ad797176afedb9262fdea4507d0fc60eb9dMike Reed    if (SkBlendMode::kDst == mode ||
1907d954ad797176afedb9262fdea4507d0fc60eb9dMike Reed        (0 == alpha && (SkBlendMode::kSrcOver == mode ||
1917d954ad797176afedb9262fdea4507d0fc60eb9dMike Reed                        SkBlendMode::kDstOver == mode ||
1927d954ad797176afedb9262fdea4507d0fc60eb9dMike Reed                        SkBlendMode::kDstOut == mode ||
1937d954ad797176afedb9262fdea4507d0fc60eb9dMike Reed                        SkBlendMode::kSrcATop == mode ||
1947d954ad797176afedb9262fdea4507d0fc60eb9dMike Reed                        SkBlendMode::kXor == mode ||
1957d954ad797176afedb9262fdea4507d0fc60eb9dMike Reed                        SkBlendMode::kDarken == mode)) ||
1967d954ad797176afedb9262fdea4507d0fc60eb9dMike Reed            (0xFF == alpha && SkBlendMode::kDstIn == mode)) {
19796fcdcc219d2a0d3579719b84b28bede76efba64halcanary        return nullptr;
1988a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
1991447c6f7f4579942b32af6ffff1eadede40b42bctomhudson@google.com
2008a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    switch (mode) {
2017d954ad797176afedb9262fdea4507d0fc60eb9dMike Reed        case SkBlendMode::kSrc:
202d053ce9c54d4e5937a142278359e5a4cde18095ereed            return sk_make_sp<Src_SkModeColorFilter>(color);
2037d954ad797176afedb9262fdea4507d0fc60eb9dMike Reed        case SkBlendMode::kSrcOver:
204d053ce9c54d4e5937a142278359e5a4cde18095ereed            return sk_make_sp<SrcOver_SkModeColorFilter>(color);
20543c50c8c77df82c5cffb55cae2d386e59802b88freed@google.com        default:
206d053ce9c54d4e5937a142278359e5a4cde18095ereed            return SkModeColorFilter::Make(color, mode);
2078a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
2088a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
209