aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/core/SkColorSpaceXformImageGenerator.cpp
blob: 79b4650625f9db8d1456307abd49da9d9a3886c9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
/*
 * Copyright 2017 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "SkColorSpaceXformImageGenerator.h"

std::unique_ptr<SkImageGenerator> SkColorSpaceXformImageGenerator::Make(
        const SkBitmap& src, sk_sp<SkColorSpace> dst, SkCopyPixelsMode mode) {
    return SkColorSpaceXformImageGenerator::Make(src, dst, mode, kNeedNewImageUniqueID);
}

std::unique_ptr<SkImageGenerator> SkColorSpaceXformImageGenerator::Make(
        const SkBitmap& src, sk_sp<SkColorSpace> dst, SkCopyPixelsMode mode, uint32_t id) {
    if (!dst) {
        return nullptr;
    }

    const SkBitmap* srcPtr = &src;
    SkBitmap copy;
    if (kAlways_SkCopyPixelsMode == mode ||
            (kNever_SkCopyPixelsMode != mode && !src.isImmutable())) {
        if (!copy.tryAllocPixels(src.info())) {
            return nullptr;
        }

        SkAssertResult(src.readPixels(copy.info(), copy.getPixels(), copy.rowBytes(), 0, 0));
        copy.setImmutable();
        srcPtr = &copy;
    }

    return std::unique_ptr<SkImageGenerator>(
            new SkColorSpaceXformImageGenerator(*srcPtr, std::move(dst), id));
}

SkColorSpaceXformImageGenerator::SkColorSpaceXformImageGenerator(const SkBitmap& src,
                                                                 sk_sp<SkColorSpace> dst,
                                                                 uint32_t id)
    : INHERITED(src.info().makeColorSpace(dst), id)
    , fSrc(src)
    , fDst(std::move(dst))
{}

bool SkColorSpaceXformImageGenerator::onGetPixels(const SkImageInfo& info, void* pixels,
                                                  size_t rowBytes, const Options& opts) {
    SkImageInfo dstInfo = info;
    if (!info.colorSpace()) {
        dstInfo = dstInfo.makeColorSpace(fDst);
    }
    return fSrc.readPixels(dstInfo, pixels, rowBytes, 0, 0, opts.fBehavior);
}

#if SK_SUPPORT_GPU

#include "GrClip.h"
#include "GrContext.h"
#include "GrPaint.h"
#include "GrRenderTargetContext.h"
#include "GrTextureProxy.h"
#include "SkGr.h"
#include "effects/GrNonlinearColorSpaceXformEffect.h"

sk_sp<GrTextureProxy> SkColorSpaceXformImageGenerator::onGenerateTexture(GrContext* ctx,
                                                                         const SkImageInfo& info,
                                                                         const SkIPoint& origin) {
    // FIXME:
    // This always operates as if SkTranferFunctionBehavior is kIgnore.  Should we add
    // options so that caller can also request kRespect?

    SkASSERT(ctx);

    sk_sp<GrTextureProxy> proxy = GrUploadBitmapToTextureProxy(ctx->resourceProvider(),
                                                               fSrc, nullptr);

    sk_sp<SkColorSpace> srcSpace =
            fSrc.colorSpace() ? sk_ref_sp(fSrc.colorSpace()) : SkColorSpace::MakeSRGB();
    auto xform = GrNonlinearColorSpaceXformEffect::Make(srcSpace.get(), fDst.get());
    if (!xform) {
        return nullptr;
    }

    sk_sp<GrRenderTargetContext> renderTargetContext = ctx->makeDeferredRenderTargetContext(
            SkBackingFit::kExact, fSrc.width(), fSrc.height(), kRGBA_8888_GrPixelConfig, nullptr);
    if (!renderTargetContext) {
        return nullptr;
    }

    GrPaint paint;
    paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
    paint.addColorTextureProcessor(std::move(proxy), nullptr,
                                   SkMatrix::MakeTrans(origin.fX, origin.fY));
    paint.addColorFragmentProcessor(std::move(xform));

    const SkRect rect = SkRect::MakeWH(info.width(), info.height());
    renderTargetContext->drawRect(GrNoClip(), std::move(paint), GrAA::kNo, SkMatrix::I(), rect);
    return sk_ref_sp(renderTargetContext->asTextureProxy());
}

#endif