Update rive-cpp to 2.0 version
[platform/core/uifw/rive-tizen.git] / submodule / skia / src / utils / SkAnimCodecPlayer.cpp
1 /*
2  * Copyright 2018 Google Inc.
3  *
4  * Use of this source code is governed by a BSD-style license that can be
5  * found in the LICENSE file.
6  */
7
8 #include "include/utils/SkAnimCodecPlayer.h"
9
10 #include "include/codec/SkCodec.h"
11 #include "include/codec/SkEncodedOrigin.h"
12 #include "include/core/SkAlphaType.h"
13 #include "include/core/SkBlendMode.h"
14 #include "include/core/SkCanvas.h"
15 #include "include/core/SkData.h"
16 #include "include/core/SkImage.h"
17 #include "include/core/SkImageInfo.h"
18 #include "include/core/SkMatrix.h"
19 #include "include/core/SkPaint.h"
20 #include "include/core/SkRefCnt.h"
21 #include "include/core/SkSamplingOptions.h"
22 #include "include/core/SkSize.h"
23 #include "include/core/SkTypes.h"
24 #include "src/codec/SkCodecImageGenerator.h"
25
26 #include <algorithm>
27 #include <memory>
28 #include <utility>
29 #include <vector>
30
31 SkAnimCodecPlayer::SkAnimCodecPlayer(std::unique_ptr<SkCodec> codec) : fCodec(std::move(codec)) {
32     fImageInfo = fCodec->getInfo();
33     fFrameInfos = fCodec->getFrameInfo();
34     fImages.resize(fFrameInfos.size());
35
36     // change the interpretation of fDuration to a end-time for that frame
37     size_t dur = 0;
38     for (auto& f : fFrameInfos) {
39         dur += f.fDuration;
40         f.fDuration = dur;
41     }
42     fTotalDuration = dur;
43
44     if (!fTotalDuration) {
45         // Static image -- may or may not have returned a single frame info.
46         fFrameInfos.clear();
47         fImages.clear();
48         fImages.push_back(SkImage::MakeFromGenerator(
49                               SkCodecImageGenerator::MakeFromCodec(std::move(fCodec))));
50     }
51 }
52
53 SkAnimCodecPlayer::~SkAnimCodecPlayer() {}
54
55 SkISize SkAnimCodecPlayer::dimensions() const {
56     if (!fCodec) {
57         auto image = fImages.front();
58         return image ? image->dimensions() : SkISize::MakeEmpty();
59     }
60     if (SkEncodedOriginSwapsWidthHeight(fCodec->getOrigin())) {
61         return { fImageInfo.height(), fImageInfo.width() };
62     }
63     return { fImageInfo.width(), fImageInfo.height() };
64 }
65
66 sk_sp<SkImage> SkAnimCodecPlayer::getFrameAt(int index) {
67     SkASSERT((unsigned)index < fFrameInfos.size());
68
69     if (fImages[index]) {
70         return fImages[index];
71     }
72
73     size_t rb = fImageInfo.minRowBytes();
74     size_t size = fImageInfo.computeByteSize(rb);
75     auto data = SkData::MakeUninitialized(size);
76
77     SkCodec::Options opts;
78     opts.fFrameIndex = index;
79
80     const auto origin = fCodec->getOrigin();
81     const auto orientedDims = this->dimensions();
82     const auto originMatrix = SkEncodedOriginToMatrix(origin, orientedDims.width(),
83                                                               orientedDims.height());
84
85     SkPaint paint;
86     paint.setBlendMode(SkBlendMode::kSrc);
87
88     auto imageInfo = fImageInfo;
89     if (fFrameInfos[index].fAlphaType != kOpaque_SkAlphaType && imageInfo.isOpaque()) {
90         imageInfo = imageInfo.makeAlphaType(kPremul_SkAlphaType);
91     }
92     const int requiredFrame = fFrameInfos[index].fRequiredFrame;
93     if (requiredFrame != SkCodec::kNoFrame && fImages[requiredFrame]) {
94         auto requiredImage = fImages[requiredFrame];
95         auto canvas = SkCanvas::MakeRasterDirect(imageInfo, data->writable_data(), rb);
96         if (origin != kDefault_SkEncodedOrigin) {
97             // The required frame is stored after applying the origin. Undo that,
98             // because the codec decodes prior to applying the origin.
99             // FIXME: Another approach would be to decode the frame's delta on top
100             // of transparent black, and then draw that through the origin matrix
101             // onto the required frame. To do that, SkCodec needs to expose the
102             // rectangle of the delta and the blend mode, so we can handle
103             // kRestoreBGColor frames and Blend::kSrc.
104             SkMatrix inverse;
105             SkAssertResult(originMatrix.invert(&inverse));
106             canvas->concat(inverse);
107         }
108         canvas->drawImage(requiredImage, 0, 0, SkSamplingOptions(), &paint);
109         opts.fPriorFrame = requiredFrame;
110     }
111
112     if (SkCodec::kSuccess != fCodec->getPixels(imageInfo, data->writable_data(), rb, &opts)) {
113         return nullptr;
114     }
115
116     auto image = SkImage::MakeRasterData(imageInfo, std::move(data), rb);
117     if (origin != kDefault_SkEncodedOrigin) {
118         imageInfo = imageInfo.makeDimensions(orientedDims);
119         rb = imageInfo.minRowBytes();
120         size = imageInfo.computeByteSize(rb);
121         data = SkData::MakeUninitialized(size);
122         auto canvas = SkCanvas::MakeRasterDirect(imageInfo, data->writable_data(), rb);
123         canvas->concat(originMatrix);
124         canvas->drawImage(image, 0, 0, SkSamplingOptions(), &paint);
125         image = SkImage::MakeRasterData(imageInfo, std::move(data), rb);
126     }
127     return fImages[index] = image;
128 }
129
130 sk_sp<SkImage> SkAnimCodecPlayer::getFrame() {
131     SkASSERT(fTotalDuration > 0 || fImages.size() == 1);
132
133     return fTotalDuration > 0
134         ? this->getFrameAt(fCurrIndex)
135         : fImages.front();
136 }
137
138 bool SkAnimCodecPlayer::seek(uint32_t msec) {
139     if (!fTotalDuration) {
140         return false;
141     }
142
143     msec %= fTotalDuration;
144
145     auto lower = std::lower_bound(fFrameInfos.begin(), fFrameInfos.end(), msec,
146                                   [](const SkCodec::FrameInfo& info, uint32_t msec) {
147                                       return (uint32_t)info.fDuration <= msec;
148                                   });
149     int prevIndex = fCurrIndex;
150     fCurrIndex = lower - fFrameInfos.begin();
151     return fCurrIndex != prevIndex;
152 }
153
154