1883fe7f8b13be4ae3e3f8d8f8a6d6e94d13f9392tfarina@chromium.org/*
2883fe7f8b13be4ae3e3f8d8f8a6d6e94d13f9392tfarina@chromium.org * Copyright 2013 Google Inc.
3883fe7f8b13be4ae3e3f8d8f8a6d6e94d13f9392tfarina@chromium.org *
4883fe7f8b13be4ae3e3f8d8f8a6d6e94d13f9392tfarina@chromium.org * Use of this source code is governed by a BSD-style license that can be
5883fe7f8b13be4ae3e3f8d8f8a6d6e94d13f9392tfarina@chromium.org * found in the LICENSE file.
6883fe7f8b13be4ae3e3f8d8f8a6d6e94d13f9392tfarina@chromium.org */
7883fe7f8b13be4ae3e3f8d8f8a6d6e94d13f9392tfarina@chromium.org
8883fe7f8b13be4ae3e3f8d8f8a6d6e94d13f9392tfarina@chromium.org#include "SkFilterShader.h"
9883fe7f8b13be4ae3e3f8d8f8a6d6e94d13f9392tfarina@chromium.org
10883fe7f8b13be4ae3e3f8d8f8a6d6e94d13f9392tfarina@chromium.org#include "SkColorFilter.h"
118b0e8ac5f582de80356019406e2975079bf0829dcommit-bot@chromium.org#include "SkReadBuffer.h"
128b0e8ac5f582de80356019406e2975079bf0829dcommit-bot@chromium.org#include "SkWriteBuffer.h"
13883fe7f8b13be4ae3e3f8d8f8a6d6e94d13f9392tfarina@chromium.org#include "SkShader.h"
14883fe7f8b13be4ae3e3f8d8f8a6d6e94d13f9392tfarina@chromium.org#include "SkString.h"
15883fe7f8b13be4ae3e3f8d8f8a6d6e94d13f9392tfarina@chromium.org
16883fe7f8b13be4ae3e3f8d8f8a6d6e94d13f9392tfarina@chromium.orgSkFilterShader::SkFilterShader(SkShader* shader, SkColorFilter* filter) {
17883fe7f8b13be4ae3e3f8d8f8a6d6e94d13f9392tfarina@chromium.org    fShader = shader;
18883fe7f8b13be4ae3e3f8d8f8a6d6e94d13f9392tfarina@chromium.org    shader->ref();
19883fe7f8b13be4ae3e3f8d8f8a6d6e94d13f9392tfarina@chromium.org
20883fe7f8b13be4ae3e3f8d8f8a6d6e94d13f9392tfarina@chromium.org    fFilter = filter;
21883fe7f8b13be4ae3e3f8d8f8a6d6e94d13f9392tfarina@chromium.org    filter->ref();
22883fe7f8b13be4ae3e3f8d8f8a6d6e94d13f9392tfarina@chromium.org}
23883fe7f8b13be4ae3e3f8d8f8a6d6e94d13f9392tfarina@chromium.org
249fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed#ifdef SK_SUPPORT_LEGACY_DEEPFLATTENING
259fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reedSkFilterShader::SkFilterShader(SkReadBuffer& buffer) : INHERITED(buffer) {
26353482251e61971a8cf3a60bbb6910f482be634freed@google.com    fShader = buffer.readShader();
27353482251e61971a8cf3a60bbb6910f482be634freed@google.com    fFilter = buffer.readColorFilter();
28883fe7f8b13be4ae3e3f8d8f8a6d6e94d13f9392tfarina@chromium.org}
299fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed#endif
30883fe7f8b13be4ae3e3f8d8f8a6d6e94d13f9392tfarina@chromium.org
31883fe7f8b13be4ae3e3f8d8f8a6d6e94d13f9392tfarina@chromium.orgSkFilterShader::~SkFilterShader() {
32883fe7f8b13be4ae3e3f8d8f8a6d6e94d13f9392tfarina@chromium.org    fFilter->unref();
33883fe7f8b13be4ae3e3f8d8f8a6d6e94d13f9392tfarina@chromium.org    fShader->unref();
34883fe7f8b13be4ae3e3f8d8f8a6d6e94d13f9392tfarina@chromium.org}
35883fe7f8b13be4ae3e3f8d8f8a6d6e94d13f9392tfarina@chromium.org
369fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reedSkFlattenable* SkFilterShader::CreateProc(SkReadBuffer& buffer) {
379fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed    SkAutoTUnref<SkShader> shader(buffer.readShader());
389fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed    SkAutoTUnref<SkColorFilter> filter(buffer.readColorFilter());
399fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed    if (!shader.get() || !filter.get()) {
409fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed        return NULL;
419fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed    }
429fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed    return SkNEW_ARGS(SkFilterShader, (shader, filter));
439fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed}
449fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed
458b0e8ac5f582de80356019406e2975079bf0829dcommit-bot@chromium.orgvoid SkFilterShader::flatten(SkWriteBuffer& buffer) const {
46883fe7f8b13be4ae3e3f8d8f8a6d6e94d13f9392tfarina@chromium.org    buffer.writeFlattenable(fShader);
47883fe7f8b13be4ae3e3f8d8f8a6d6e94d13f9392tfarina@chromium.org    buffer.writeFlattenable(fFilter);
48883fe7f8b13be4ae3e3f8d8f8a6d6e94d13f9392tfarina@chromium.org}
49883fe7f8b13be4ae3e3f8d8f8a6d6e94d13f9392tfarina@chromium.org
5087fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.orguint32_t SkFilterShader::FilterShaderContext::getFlags() const {
5187fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org    const SkFilterShader& filterShader = static_cast<const SkFilterShader&>(fShader);
5287fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org
5387fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org    uint32_t shaderF = fShaderContext->getFlags();
5487fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org    uint32_t filterF = filterShader.fFilter->getFlags();
55883fe7f8b13be4ae3e3f8d8f8a6d6e94d13f9392tfarina@chromium.org
56883fe7f8b13be4ae3e3f8d8f8a6d6e94d13f9392tfarina@chromium.org    // if the filter doesn't support 16bit, clear the matching bit in the shader
57883fe7f8b13be4ae3e3f8d8f8a6d6e94d13f9392tfarina@chromium.org    if (!(filterF & SkColorFilter::kHasFilter16_Flag)) {
58883fe7f8b13be4ae3e3f8d8f8a6d6e94d13f9392tfarina@chromium.org        shaderF &= ~SkShader::kHasSpan16_Flag;
59883fe7f8b13be4ae3e3f8d8f8a6d6e94d13f9392tfarina@chromium.org    }
60883fe7f8b13be4ae3e3f8d8f8a6d6e94d13f9392tfarina@chromium.org    // if the filter might change alpha, clear the opaque flag in the shader
61883fe7f8b13be4ae3e3f8d8f8a6d6e94d13f9392tfarina@chromium.org    if (!(filterF & SkColorFilter::kAlphaUnchanged_Flag)) {
62883fe7f8b13be4ae3e3f8d8f8a6d6e94d13f9392tfarina@chromium.org        shaderF &= ~(SkShader::kOpaqueAlpha_Flag | SkShader::kHasSpan16_Flag);
63883fe7f8b13be4ae3e3f8d8f8a6d6e94d13f9392tfarina@chromium.org    }
64883fe7f8b13be4ae3e3f8d8f8a6d6e94d13f9392tfarina@chromium.org    return shaderF;
65883fe7f8b13be4ae3e3f8d8f8a6d6e94d13f9392tfarina@chromium.org}
66883fe7f8b13be4ae3e3f8d8f8a6d6e94d13f9392tfarina@chromium.org
67ce56d965069c1649afe14319cb239e6ad670682acommit-bot@chromium.orgSkShader::Context* SkFilterShader::onCreateContext(const ContextRec& rec, void* storage) const {
6887fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org    char* shaderContextStorage = (char*)storage + sizeof(FilterShaderContext);
69e901b6de3ef8dea842008a08fc81e92fb1478d61commit-bot@chromium.org    SkShader::Context* shaderContext = fShader->createContext(rec, shaderContextStorage);
70a69bda8d3c0901aaa4fa683dcd2adda5d6aa428bcommit-bot@chromium.org    if (NULL == shaderContext) {
71a69bda8d3c0901aaa4fa683dcd2adda5d6aa428bcommit-bot@chromium.org        return NULL;
72a69bda8d3c0901aaa4fa683dcd2adda5d6aa428bcommit-bot@chromium.org    }
73e901b6de3ef8dea842008a08fc81e92fb1478d61commit-bot@chromium.org    return SkNEW_PLACEMENT_ARGS(storage, FilterShaderContext, (*this, shaderContext, rec));
7487fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org}
7587fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org
7687fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.orgsize_t SkFilterShader::contextSize() const {
7787fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org    return sizeof(FilterShaderContext) + fShader->contextSize();
7887fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org}
7987fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org
8087fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.orgSkFilterShader::FilterShaderContext::FilterShaderContext(const SkFilterShader& filterShader,
8187fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org                                                         SkShader::Context* shaderContext,
82e901b6de3ef8dea842008a08fc81e92fb1478d61commit-bot@chromium.org                                                         const ContextRec& rec)
83e901b6de3ef8dea842008a08fc81e92fb1478d61commit-bot@chromium.org    : INHERITED(filterShader, rec)
8487fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org    , fShaderContext(shaderContext) {}
8587fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org
8687fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.orgSkFilterShader::FilterShaderContext::~FilterShaderContext() {
8787fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org    fShaderContext->~Context();
88883fe7f8b13be4ae3e3f8d8f8a6d6e94d13f9392tfarina@chromium.org}
89883fe7f8b13be4ae3e3f8d8f8a6d6e94d13f9392tfarina@chromium.org
9087fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.orgvoid SkFilterShader::FilterShaderContext::shadeSpan(int x, int y, SkPMColor result[], int count) {
9187fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org    const SkFilterShader& filterShader = static_cast<const SkFilterShader&>(fShader);
9287fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org
9387fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org    fShaderContext->shadeSpan(x, y, result, count);
9487fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org    filterShader.fFilter->filterSpan(result, count, result);
95883fe7f8b13be4ae3e3f8d8f8a6d6e94d13f9392tfarina@chromium.org}
96883fe7f8b13be4ae3e3f8d8f8a6d6e94d13f9392tfarina@chromium.org
9787fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.orgvoid SkFilterShader::FilterShaderContext::shadeSpan16(int x, int y, uint16_t result[], int count) {
9887fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org    const SkFilterShader& filterShader = static_cast<const SkFilterShader&>(fShader);
9987fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org
10087fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org    SkASSERT(fShaderContext->getFlags() & SkShader::kHasSpan16_Flag);
10187fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org    SkASSERT(filterShader.fFilter->getFlags() & SkColorFilter::kHasFilter16_Flag);
102883fe7f8b13be4ae3e3f8d8f8a6d6e94d13f9392tfarina@chromium.org
10387fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org    fShaderContext->shadeSpan16(x, y, result, count);
10487fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org    filterShader.fFilter->filterSpan16(result, count, result);
105883fe7f8b13be4ae3e3f8d8f8a6d6e94d13f9392tfarina@chromium.org}
106883fe7f8b13be4ae3e3f8d8f8a6d6e94d13f9392tfarina@chromium.org
1070f10f7bf1fb43ca6346dc220a076773b1f19a367commit-bot@chromium.org#ifndef SK_IGNORE_TO_STRING
108883fe7f8b13be4ae3e3f8d8f8a6d6e94d13f9392tfarina@chromium.orgvoid SkFilterShader::toString(SkString* str) const {
109883fe7f8b13be4ae3e3f8d8f8a6d6e94d13f9392tfarina@chromium.org    str->append("SkFilterShader: (");
110883fe7f8b13be4ae3e3f8d8f8a6d6e94d13f9392tfarina@chromium.org
111883fe7f8b13be4ae3e3f8d8f8a6d6e94d13f9392tfarina@chromium.org    str->append("Shader: ");
112883fe7f8b13be4ae3e3f8d8f8a6d6e94d13f9392tfarina@chromium.org    fShader->toString(str);
113883fe7f8b13be4ae3e3f8d8f8a6d6e94d13f9392tfarina@chromium.org    str->append(" Filter: ");
114883fe7f8b13be4ae3e3f8d8f8a6d6e94d13f9392tfarina@chromium.org    // TODO: add "fFilter->toString(str);" once SkColorFilter::toString is added
115883fe7f8b13be4ae3e3f8d8f8a6d6e94d13f9392tfarina@chromium.org
116883fe7f8b13be4ae3e3f8d8f8a6d6e94d13f9392tfarina@chromium.org    this->INHERITED::toString(str);
117883fe7f8b13be4ae3e3f8d8f8a6d6e94d13f9392tfarina@chromium.org
118883fe7f8b13be4ae3e3f8d8f8a6d6e94d13f9392tfarina@chromium.org    str->append(")");
119883fe7f8b13be4ae3e3f8d8f8a6d6e94d13f9392tfarina@chromium.org}
120883fe7f8b13be4ae3e3f8d8f8a6d6e94d13f9392tfarina@chromium.org#endif
121