1/*
2 * Copyright 2017 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#ifndef SkFrameHolder_DEFINED
9#define SkFrameHolder_DEFINED
10
11#include "SkTypes.h"
12#include "SkCodecAnimation.h"
13#include "SkCodecAnimationPriv.h"
14#include "SkRect.h"
15
16/**
17 *  Base class for a single frame of an animated image.
18 *
19 *  Separate from SkCodec::FrameInfo, which is a pared down
20 *  interface that only contains the info the client needs.
21 */
22class SkFrame : public SkNoncopyable {
23public:
24    SkFrame(int id)
25        : fId(id)
26        , fHasAlpha(false)
27        , fRequiredFrame(kUninitialized)
28        , fDisposalMethod(SkCodecAnimation::DisposalMethod::kKeep)
29        , fDuration(0)
30        , fBlend(SkCodecAnimation::Blend::kPriorFrame)
31    {
32        fRect.setEmpty();
33    }
34
35    virtual ~SkFrame() {}
36
37    /**
38     *  0-based index of the frame in the image sequence.
39     */
40    int frameId() const { return fId; }
41
42    /**
43     *  How this frame reports its alpha.
44     *
45     *  This only considers the rectangle of this frame, and
46     *  considers it to have alpha even if it is opaque once
47     *  blended with the frame behind it.
48     */
49    SkEncodedInfo::Alpha reportedAlpha() const {
50        return this->onReportedAlpha();
51    }
52
53    /**
54     *  Cached value representing whether the frame has alpha,
55     *  after compositing with the prior frame.
56     */
57    bool hasAlpha() const { return fHasAlpha; }
58
59    /**
60     *  Cache whether the finished frame has alpha.
61     */
62    void setHasAlpha(bool alpha) { fHasAlpha = alpha; }
63
64    /**
65     *  Whether enough of the frame has been read to determine
66     *  fRequiredFrame and fHasAlpha.
67     */
68    bool reachedStartOfData() const { return fRequiredFrame != kUninitialized; }
69
70    /**
71     *  The frame this one depends on.
72     *
73     *  Must not be called until fRequiredFrame has been set properly.
74     */
75    int getRequiredFrame() const {
76        SkASSERT(this->reachedStartOfData());
77        return fRequiredFrame;
78    }
79
80    /**
81     *  Set the frame that this frame depends on.
82     */
83    void setRequiredFrame(int req) { fRequiredFrame = req; }
84
85    /**
86     *  Set the rectangle that is updated by this frame.
87     */
88    void setXYWH(int x, int y, int width, int height) {
89        fRect.setXYWH(x, y, width, height);
90    }
91
92    /**
93     *  The rectangle that is updated by this frame.
94     */
95    SkIRect frameRect() const { return fRect; }
96
97    int xOffset() const { return fRect.x(); }
98    int yOffset() const { return fRect.y(); }
99    int width()   const { return fRect.width(); }
100    int height()  const { return fRect.height(); }
101
102    SkCodecAnimation::DisposalMethod getDisposalMethod() const {
103        return fDisposalMethod;
104    }
105
106    void setDisposalMethod(SkCodecAnimation::DisposalMethod disposalMethod) {
107        fDisposalMethod = disposalMethod;
108    }
109
110    /**
111     * Set the duration (in ms) to show this frame.
112     */
113    void setDuration(int duration) {
114        fDuration = duration;
115    }
116
117    /**
118     *  Duration in ms to show this frame.
119     */
120    int getDuration() const {
121        return fDuration;
122    }
123
124    void setBlend(SkCodecAnimation::Blend blend) {
125        fBlend = blend;
126    }
127
128    SkCodecAnimation::Blend getBlend() const {
129        return fBlend;
130    }
131
132protected:
133    virtual SkEncodedInfo::Alpha onReportedAlpha() const = 0;
134
135private:
136    static constexpr int kUninitialized = -2;
137
138    const int                           fId;
139    bool                                fHasAlpha;
140    int                                 fRequiredFrame;
141    SkIRect                             fRect;
142    SkCodecAnimation::DisposalMethod    fDisposalMethod;
143    int                                 fDuration;
144    SkCodecAnimation::Blend             fBlend;
145};
146
147/**
148 *  Base class for an object which holds the SkFrames of an
149 *  image sequence.
150 */
151class SkFrameHolder : public SkNoncopyable {
152public:
153    SkFrameHolder()
154        : fScreenWidth(0)
155        , fScreenHeight(0)
156    {}
157
158    virtual ~SkFrameHolder() {}
159
160    /**
161     *  Size of the image. Each frame will be contained in
162     *  these dimensions (possibly after clipping).
163     */
164    int screenWidth() const { return fScreenWidth; }
165    int screenHeight() const { return fScreenHeight; }
166
167    /**
168     *  Compute the opacity and required frame, based on
169     *  the frame's reportedAlpha and how it blends
170     *  with prior frames.
171     */
172    void setAlphaAndRequiredFrame(SkFrame*);
173
174    /**
175     *  Return the frame with frameId i.
176     */
177    const SkFrame* getFrame(int i) const {
178        return this->onGetFrame(i);
179    }
180
181protected:
182    int fScreenWidth;
183    int fScreenHeight;
184
185    virtual const SkFrame* onGetFrame(int i) const = 0;
186};
187
188#endif // SkFrameHolder_DEFINED
189