1cb93a386Sopenharmony_ci/*
2cb93a386Sopenharmony_ci * Copyright 2016 Google Inc.
3cb93a386Sopenharmony_ci *
4cb93a386Sopenharmony_ci * Use of this source code is governed by a BSD-style license that can be
5cb93a386Sopenharmony_ci * found in the LICENSE file.
6cb93a386Sopenharmony_ci */
7cb93a386Sopenharmony_ci
8cb93a386Sopenharmony_ci#include "include/codec/SkEncodedOrigin.h"
9cb93a386Sopenharmony_ci#include "include/ports/SkImageGeneratorCG.h"
10cb93a386Sopenharmony_ci#include "include/private/SkTemplates.h"
11cb93a386Sopenharmony_ci#include "include/utils/mac/SkCGUtils.h"
12cb93a386Sopenharmony_ci#include "src/core/SkPixmapPriv.h"
13cb93a386Sopenharmony_ci#include "src/utils/mac/SkUniqueCFRef.h"
14cb93a386Sopenharmony_ci
15cb93a386Sopenharmony_ci#ifdef SK_BUILD_FOR_MAC
16cb93a386Sopenharmony_ci#include <ApplicationServices/ApplicationServices.h>
17cb93a386Sopenharmony_ci#endif
18cb93a386Sopenharmony_ci
19cb93a386Sopenharmony_ci#ifdef SK_BUILD_FOR_IOS
20cb93a386Sopenharmony_ci#include <CoreGraphics/CoreGraphics.h>
21cb93a386Sopenharmony_ci#include <ImageIO/ImageIO.h>
22cb93a386Sopenharmony_ci#include <MobileCoreServices/MobileCoreServices.h>
23cb93a386Sopenharmony_ci#endif
24cb93a386Sopenharmony_ci
25cb93a386Sopenharmony_cinamespace {
26cb93a386Sopenharmony_ciclass ImageGeneratorCG : public SkImageGenerator {
27cb93a386Sopenharmony_cipublic:
28cb93a386Sopenharmony_ci    ImageGeneratorCG(const SkImageInfo&, SkUniqueCFRef<CGImageSourceRef> imageSrc,
29cb93a386Sopenharmony_ci                     sk_sp<SkData> data, SkEncodedOrigin);
30cb93a386Sopenharmony_ci
31cb93a386Sopenharmony_ciprotected:
32cb93a386Sopenharmony_ci    sk_sp<SkData> onRefEncodedData() override;
33cb93a386Sopenharmony_ci
34cb93a386Sopenharmony_ci    bool onGetPixels(const SkImageInfo&, void* pixels, size_t rowBytes, const Options&) override;
35cb93a386Sopenharmony_ci
36cb93a386Sopenharmony_ciprivate:
37cb93a386Sopenharmony_ci    const SkUniqueCFRef<CGImageSourceRef> fImageSrc;
38cb93a386Sopenharmony_ci    const sk_sp<SkData> fData;
39cb93a386Sopenharmony_ci    const SkEncodedOrigin fOrigin;
40cb93a386Sopenharmony_ci
41cb93a386Sopenharmony_ci    using INHERITED = SkImageGenerator;
42cb93a386Sopenharmony_ci};
43cb93a386Sopenharmony_ci
44cb93a386Sopenharmony_cistatic SkUniqueCFRef<CGImageSourceRef> data_to_CGImageSrc(SkData* data) {
45cb93a386Sopenharmony_ci    SkUniqueCFRef<CGDataProviderRef> cgData(
46cb93a386Sopenharmony_ci            CGDataProviderCreateWithData(data, data->data(), data->size(), nullptr));
47cb93a386Sopenharmony_ci    if (!cgData) {
48cb93a386Sopenharmony_ci        return nullptr;
49cb93a386Sopenharmony_ci    }
50cb93a386Sopenharmony_ci    return SkUniqueCFRef<CGImageSourceRef>(
51cb93a386Sopenharmony_ci            CGImageSourceCreateWithDataProvider(cgData.get(), nullptr));
52cb93a386Sopenharmony_ci}
53cb93a386Sopenharmony_ci
54cb93a386Sopenharmony_ci}  // namespace
55cb93a386Sopenharmony_ci
56cb93a386Sopenharmony_cistd::unique_ptr<SkImageGenerator> SkImageGeneratorCG::MakeFromEncodedCG(sk_sp<SkData> data) {
57cb93a386Sopenharmony_ci    SkUniqueCFRef<CGImageSourceRef> imageSrc = data_to_CGImageSrc(data.get());
58cb93a386Sopenharmony_ci    if (!imageSrc) {
59cb93a386Sopenharmony_ci        return nullptr;
60cb93a386Sopenharmony_ci    }
61cb93a386Sopenharmony_ci
62cb93a386Sopenharmony_ci    SkUniqueCFRef<CFDictionaryRef> properties(
63cb93a386Sopenharmony_ci            CGImageSourceCopyPropertiesAtIndex(imageSrc.get(), 0, nullptr));
64cb93a386Sopenharmony_ci    if (!properties) {
65cb93a386Sopenharmony_ci        return nullptr;
66cb93a386Sopenharmony_ci    }
67cb93a386Sopenharmony_ci
68cb93a386Sopenharmony_ci    CFNumberRef widthRef = static_cast<CFNumberRef>(
69cb93a386Sopenharmony_ci            CFDictionaryGetValue(properties.get(), kCGImagePropertyPixelWidth));
70cb93a386Sopenharmony_ci    CFNumberRef heightRef = static_cast<CFNumberRef>(
71cb93a386Sopenharmony_ci            CFDictionaryGetValue(properties.get(), kCGImagePropertyPixelHeight));
72cb93a386Sopenharmony_ci    if (nullptr == widthRef || nullptr == heightRef) {
73cb93a386Sopenharmony_ci        return nullptr;
74cb93a386Sopenharmony_ci    }
75cb93a386Sopenharmony_ci
76cb93a386Sopenharmony_ci    int width, height;
77cb93a386Sopenharmony_ci    if (!CFNumberGetValue(widthRef , kCFNumberIntType, &width ) ||
78cb93a386Sopenharmony_ci        !CFNumberGetValue(heightRef, kCFNumberIntType, &height))
79cb93a386Sopenharmony_ci    {
80cb93a386Sopenharmony_ci        return nullptr;
81cb93a386Sopenharmony_ci    }
82cb93a386Sopenharmony_ci
83cb93a386Sopenharmony_ci    bool hasAlpha = bool(CFDictionaryGetValue(properties.get(), kCGImagePropertyHasAlpha));
84cb93a386Sopenharmony_ci    SkAlphaType alphaType = hasAlpha ? kPremul_SkAlphaType : kOpaque_SkAlphaType;
85cb93a386Sopenharmony_ci    SkImageInfo info = SkImageInfo::MakeS32(width, height, alphaType);
86cb93a386Sopenharmony_ci
87cb93a386Sopenharmony_ci    SkEncodedOrigin origin = kDefault_SkEncodedOrigin;
88cb93a386Sopenharmony_ci    CFNumberRef orientationRef = static_cast<CFNumberRef>(
89cb93a386Sopenharmony_ci            CFDictionaryGetValue(properties.get(), kCGImagePropertyOrientation));
90cb93a386Sopenharmony_ci    int originInt;
91cb93a386Sopenharmony_ci    if (orientationRef && CFNumberGetValue(orientationRef, kCFNumberIntType, &originInt)) {
92cb93a386Sopenharmony_ci        origin = (SkEncodedOrigin) originInt;
93cb93a386Sopenharmony_ci    }
94cb93a386Sopenharmony_ci
95cb93a386Sopenharmony_ci    if (SkEncodedOriginSwapsWidthHeight(origin)) {
96cb93a386Sopenharmony_ci        info = SkPixmapPriv::SwapWidthHeight(info);
97cb93a386Sopenharmony_ci    }
98cb93a386Sopenharmony_ci
99cb93a386Sopenharmony_ci    // FIXME: We have the opportunity to extract color space information here,
100cb93a386Sopenharmony_ci    //        though I think it makes sense to wait until we understand how
101cb93a386Sopenharmony_ci    //        we want to communicate it to the generator.
102cb93a386Sopenharmony_ci
103cb93a386Sopenharmony_ci    return std::unique_ptr<SkImageGenerator>(new ImageGeneratorCG(info, std::move(imageSrc),
104cb93a386Sopenharmony_ci                                                                  std::move(data), origin));
105cb93a386Sopenharmony_ci}
106cb93a386Sopenharmony_ci
107cb93a386Sopenharmony_ciImageGeneratorCG::ImageGeneratorCG(const SkImageInfo& info, SkUniqueCFRef<CGImageSourceRef> src,
108cb93a386Sopenharmony_ci                                   sk_sp<SkData> data, SkEncodedOrigin origin)
109cb93a386Sopenharmony_ci    : INHERITED(info)
110cb93a386Sopenharmony_ci    , fImageSrc(std::move(src))
111cb93a386Sopenharmony_ci    , fData(std::move(data))
112cb93a386Sopenharmony_ci    , fOrigin(origin)
113cb93a386Sopenharmony_ci{}
114cb93a386Sopenharmony_ci
115cb93a386Sopenharmony_cisk_sp<SkData> ImageGeneratorCG::onRefEncodedData() {
116cb93a386Sopenharmony_ci    return fData;
117cb93a386Sopenharmony_ci}
118cb93a386Sopenharmony_ci
119cb93a386Sopenharmony_cibool ImageGeneratorCG::onGetPixels(const SkImageInfo& info, void* pixels, size_t rowBytes,
120cb93a386Sopenharmony_ci                                   const Options&)
121cb93a386Sopenharmony_ci{
122cb93a386Sopenharmony_ci    if (kN32_SkColorType != info.colorType()) {
123cb93a386Sopenharmony_ci        // FIXME: Support other colorTypes.
124cb93a386Sopenharmony_ci        return false;
125cb93a386Sopenharmony_ci    }
126cb93a386Sopenharmony_ci
127cb93a386Sopenharmony_ci    switch (info.alphaType()) {
128cb93a386Sopenharmony_ci        case kOpaque_SkAlphaType:
129cb93a386Sopenharmony_ci            if (kOpaque_SkAlphaType != this->getInfo().alphaType()) {
130cb93a386Sopenharmony_ci                return false;
131cb93a386Sopenharmony_ci            }
132cb93a386Sopenharmony_ci            break;
133cb93a386Sopenharmony_ci        case kPremul_SkAlphaType:
134cb93a386Sopenharmony_ci            break;
135cb93a386Sopenharmony_ci        default:
136cb93a386Sopenharmony_ci            return false;
137cb93a386Sopenharmony_ci    }
138cb93a386Sopenharmony_ci
139cb93a386Sopenharmony_ci    SkUniqueCFRef<CGImageRef> image(CGImageSourceCreateImageAtIndex(fImageSrc.get(), 0, nullptr));
140cb93a386Sopenharmony_ci    if (!image) {
141cb93a386Sopenharmony_ci        return false;
142cb93a386Sopenharmony_ci    }
143cb93a386Sopenharmony_ci
144cb93a386Sopenharmony_ci    SkPixmap dst(info, pixels, rowBytes);
145cb93a386Sopenharmony_ci    auto decode = [&image](const SkPixmap& pm) {
146cb93a386Sopenharmony_ci        // FIXME: Using SkCopyPixelsFromCGImage (as opposed to swizzling
147cb93a386Sopenharmony_ci        // ourselves) greatly restricts the color and alpha types that we
148cb93a386Sopenharmony_ci        // support.  If we swizzle ourselves, we can add support for:
149cb93a386Sopenharmony_ci        //     kUnpremul_SkAlphaType
150cb93a386Sopenharmony_ci        //     16-bit per component RGBA
151cb93a386Sopenharmony_ci        //     kGray_8_SkColorType
152cb93a386Sopenharmony_ci        // Additionally, it would be interesting to compare the performance
153cb93a386Sopenharmony_ci        // of SkSwizzler with CG's built in swizzler.
154cb93a386Sopenharmony_ci        return SkCopyPixelsFromCGImage(pm, image.get());
155cb93a386Sopenharmony_ci    };
156cb93a386Sopenharmony_ci    return SkPixmapPriv::Orient(dst, fOrigin, decode);
157cb93a386Sopenharmony_ci}
158