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
248b0e8ac5f582de80356019406e2975079bf0829dcommit-bot@chromium.orgSkFilterShader::SkFilterShader(SkReadBuffer& buffer)
25883fe7f8b13be4ae3e3f8d8f8a6d6e94d13f9392tfarina@chromium.org    : INHERITED(buffer) {
26353482251e61971a8cf3a60bbb6910f482be634freed@google.com    fShader = buffer.readShader();
27353482251e61971a8cf3a60bbb6910f482be634freed@google.com    fFilter = buffer.readColorFilter();
28883fe7f8b13be4ae3e3f8d8f8a6d6e94d13f9392tfarina@chromium.org}
29883fe7f8b13be4ae3e3f8d8f8a6d6e94d13f9392tfarina@chromium.org
30883fe7f8b13be4ae3e3f8d8f8a6d6e94d13f9392tfarina@chromium.orgSkFilterShader::~SkFilterShader() {
31883fe7f8b13be4ae3e3f8d8f8a6d6e94d13f9392tfarina@chromium.org    fFilter->unref();
32883fe7f8b13be4ae3e3f8d8f8a6d6e94d13f9392tfarina@chromium.org    fShader->unref();
33883fe7f8b13be4ae3e3f8d8f8a6d6e94d13f9392tfarina@chromium.org}
34883fe7f8b13be4ae3e3f8d8f8a6d6e94d13f9392tfarina@chromium.org
358b0e8ac5f582de80356019406e2975079bf0829dcommit-bot@chromium.orgvoid SkFilterShader::flatten(SkWriteBuffer& buffer) const {
36883fe7f8b13be4ae3e3f8d8f8a6d6e94d13f9392tfarina@chromium.org    this->INHERITED::flatten(buffer);
37883fe7f8b13be4ae3e3f8d8f8a6d6e94d13f9392tfarina@chromium.org    buffer.writeFlattenable(fShader);
38883fe7f8b13be4ae3e3f8d8f8a6d6e94d13f9392tfarina@chromium.org    buffer.writeFlattenable(fFilter);
39883fe7f8b13be4ae3e3f8d8f8a6d6e94d13f9392tfarina@chromium.org}
40883fe7f8b13be4ae3e3f8d8f8a6d6e94d13f9392tfarina@chromium.org
4187fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.orguint32_t SkFilterShader::FilterShaderContext::getFlags() const {
4287fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org    const SkFilterShader& filterShader = static_cast<const SkFilterShader&>(fShader);
4387fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org
4487fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org    uint32_t shaderF = fShaderContext->getFlags();
4587fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org    uint32_t filterF = filterShader.fFilter->getFlags();
46883fe7f8b13be4ae3e3f8d8f8a6d6e94d13f9392tfarina@chromium.org
47883fe7f8b13be4ae3e3f8d8f8a6d6e94d13f9392tfarina@chromium.org    // if the filter doesn't support 16bit, clear the matching bit in the shader
48883fe7f8b13be4ae3e3f8d8f8a6d6e94d13f9392tfarina@chromium.org    if (!(filterF & SkColorFilter::kHasFilter16_Flag)) {
49883fe7f8b13be4ae3e3f8d8f8a6d6e94d13f9392tfarina@chromium.org        shaderF &= ~SkShader::kHasSpan16_Flag;
50883fe7f8b13be4ae3e3f8d8f8a6d6e94d13f9392tfarina@chromium.org    }
51883fe7f8b13be4ae3e3f8d8f8a6d6e94d13f9392tfarina@chromium.org    // if the filter might change alpha, clear the opaque flag in the shader
52883fe7f8b13be4ae3e3f8d8f8a6d6e94d13f9392tfarina@chromium.org    if (!(filterF & SkColorFilter::kAlphaUnchanged_Flag)) {
53883fe7f8b13be4ae3e3f8d8f8a6d6e94d13f9392tfarina@chromium.org        shaderF &= ~(SkShader::kOpaqueAlpha_Flag | SkShader::kHasSpan16_Flag);
54883fe7f8b13be4ae3e3f8d8f8a6d6e94d13f9392tfarina@chromium.org    }
55883fe7f8b13be4ae3e3f8d8f8a6d6e94d13f9392tfarina@chromium.org    return shaderF;
56883fe7f8b13be4ae3e3f8d8f8a6d6e94d13f9392tfarina@chromium.org}
57883fe7f8b13be4ae3e3f8d8f8a6d6e94d13f9392tfarina@chromium.org
58ce56d965069c1649afe14319cb239e6ad670682acommit-bot@chromium.orgSkShader::Context* SkFilterShader::onCreateContext(const ContextRec& rec, void* storage) const {
5987fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org    char* shaderContextStorage = (char*)storage + sizeof(FilterShaderContext);
60e901b6de3ef8dea842008a08fc81e92fb1478d61commit-bot@chromium.org    SkShader::Context* shaderContext = fShader->createContext(rec, shaderContextStorage);
61a69bda8d3c0901aaa4fa683dcd2adda5d6aa428bcommit-bot@chromium.org    if (NULL == shaderContext) {
62a69bda8d3c0901aaa4fa683dcd2adda5d6aa428bcommit-bot@chromium.org        return NULL;
63a69bda8d3c0901aaa4fa683dcd2adda5d6aa428bcommit-bot@chromium.org    }
64e901b6de3ef8dea842008a08fc81e92fb1478d61commit-bot@chromium.org    return SkNEW_PLACEMENT_ARGS(storage, FilterShaderContext, (*this, shaderContext, rec));
6587fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org}
6687fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org
6787fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.orgsize_t SkFilterShader::contextSize() const {
6887fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org    return sizeof(FilterShaderContext) + fShader->contextSize();
6987fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org}
7087fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org
7187fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.orgSkFilterShader::FilterShaderContext::FilterShaderContext(const SkFilterShader& filterShader,
7287fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org                                                         SkShader::Context* shaderContext,
73e901b6de3ef8dea842008a08fc81e92fb1478d61commit-bot@chromium.org                                                         const ContextRec& rec)
74e901b6de3ef8dea842008a08fc81e92fb1478d61commit-bot@chromium.org    : INHERITED(filterShader, rec)
7587fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org    , fShaderContext(shaderContext) {}
7687fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org
7787fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.orgSkFilterShader::FilterShaderContext::~FilterShaderContext() {
7887fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org    fShaderContext->~Context();
79883fe7f8b13be4ae3e3f8d8f8a6d6e94d13f9392tfarina@chromium.org}
80883fe7f8b13be4ae3e3f8d8f8a6d6e94d13f9392tfarina@chromium.org
8187fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.orgvoid SkFilterShader::FilterShaderContext::shadeSpan(int x, int y, SkPMColor result[], int count) {
8287fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org    const SkFilterShader& filterShader = static_cast<const SkFilterShader&>(fShader);
8387fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org
8487fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org    fShaderContext->shadeSpan(x, y, result, count);
8587fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org    filterShader.fFilter->filterSpan(result, count, result);
86883fe7f8b13be4ae3e3f8d8f8a6d6e94d13f9392tfarina@chromium.org}
87883fe7f8b13be4ae3e3f8d8f8a6d6e94d13f9392tfarina@chromium.org
8887fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.orgvoid SkFilterShader::FilterShaderContext::shadeSpan16(int x, int y, uint16_t result[], int count) {
8987fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org    const SkFilterShader& filterShader = static_cast<const SkFilterShader&>(fShader);
9087fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org
9187fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org    SkASSERT(fShaderContext->getFlags() & SkShader::kHasSpan16_Flag);
9287fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org    SkASSERT(filterShader.fFilter->getFlags() & SkColorFilter::kHasFilter16_Flag);
93883fe7f8b13be4ae3e3f8d8f8a6d6e94d13f9392tfarina@chromium.org
9487fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org    fShaderContext->shadeSpan16(x, y, result, count);
9587fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org    filterShader.fFilter->filterSpan16(result, count, result);
96883fe7f8b13be4ae3e3f8d8f8a6d6e94d13f9392tfarina@chromium.org}
97883fe7f8b13be4ae3e3f8d8f8a6d6e94d13f9392tfarina@chromium.org
980f10f7bf1fb43ca6346dc220a076773b1f19a367commit-bot@chromium.org#ifndef SK_IGNORE_TO_STRING
99883fe7f8b13be4ae3e3f8d8f8a6d6e94d13f9392tfarina@chromium.orgvoid SkFilterShader::toString(SkString* str) const {
100883fe7f8b13be4ae3e3f8d8f8a6d6e94d13f9392tfarina@chromium.org    str->append("SkFilterShader: (");
101883fe7f8b13be4ae3e3f8d8f8a6d6e94d13f9392tfarina@chromium.org
102883fe7f8b13be4ae3e3f8d8f8a6d6e94d13f9392tfarina@chromium.org    str->append("Shader: ");
103883fe7f8b13be4ae3e3f8d8f8a6d6e94d13f9392tfarina@chromium.org    fShader->toString(str);
104883fe7f8b13be4ae3e3f8d8f8a6d6e94d13f9392tfarina@chromium.org    str->append(" Filter: ");
105883fe7f8b13be4ae3e3f8d8f8a6d6e94d13f9392tfarina@chromium.org    // TODO: add "fFilter->toString(str);" once SkColorFilter::toString is added
106883fe7f8b13be4ae3e3f8d8f8a6d6e94d13f9392tfarina@chromium.org
107883fe7f8b13be4ae3e3f8d8f8a6d6e94d13f9392tfarina@chromium.org    this->INHERITED::toString(str);
108883fe7f8b13be4ae3e3f8d8f8a6d6e94d13f9392tfarina@chromium.org
109883fe7f8b13be4ae3e3f8d8f8a6d6e94d13f9392tfarina@chromium.org    str->append(")");
110883fe7f8b13be4ae3e3f8d8f8a6d6e94d13f9392tfarina@chromium.org}
111883fe7f8b13be4ae3e3f8d8f8a6d6e94d13f9392tfarina@chromium.org#endif
112