Line data Source code
1 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* This Source Code Form is subject to the terms of the Mozilla Public
3 : * License, v. 2.0. If a copy of the MPL was not distributed with this
4 : * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 :
6 : #include "IDecodingTask.h"
7 :
8 : #include "gfxPrefs.h"
9 : #include "nsThreadUtils.h"
10 :
11 : #include "Decoder.h"
12 : #include "DecodePool.h"
13 : #include "RasterImage.h"
14 : #include "SurfaceCache.h"
15 :
16 : namespace mozilla {
17 :
18 : using gfx::IntRect;
19 :
20 : namespace image {
21 :
22 : ///////////////////////////////////////////////////////////////////////////////
23 : // Helpers for sending notifications to the image associated with a decoder.
24 : ///////////////////////////////////////////////////////////////////////////////
25 :
26 : /* static */ void
27 34 : IDecodingTask::NotifyProgress(NotNull<RasterImage*> aImage,
28 : NotNull<Decoder*> aDecoder)
29 : {
30 34 : MOZ_ASSERT(aDecoder->HasProgress() && !aDecoder->IsMetadataDecode());
31 :
32 : // Capture the decoder's state. If we need to notify asynchronously, it's
33 : // important that we don't wait until the lambda actually runs to capture the
34 : // state that we're going to notify. That would both introduce data races on
35 : // the decoder's state and cause inconsistencies between the NotifyProgress()
36 : // calls we make off-main-thread and the notifications that RasterImage
37 : // actually receives, which would cause bugs.
38 34 : Progress progress = aDecoder->TakeProgress();
39 34 : IntRect invalidRect = aDecoder->TakeInvalidRect();
40 68 : Maybe<uint32_t> frameCount = aDecoder->TakeCompleteFrameCount();
41 34 : DecoderFlags decoderFlags = aDecoder->GetDecoderFlags();
42 34 : SurfaceFlags surfaceFlags = aDecoder->GetSurfaceFlags();
43 :
44 : // Synchronously notify if we can.
45 34 : if (NS_IsMainThread() && !(decoderFlags & DecoderFlags::ASYNC_NOTIFY)) {
46 0 : aImage->NotifyProgress(progress, invalidRect, frameCount,
47 0 : decoderFlags, surfaceFlags);
48 0 : return;
49 : }
50 :
51 : // We're forced to notify asynchronously.
52 68 : NotNull<RefPtr<RasterImage>> image = aImage;
53 68 : NS_DispatchToMainThread(NS_NewRunnableFunction(
54 : "IDecodingTask::NotifyProgress",
55 136 : [=]() -> void {
56 34 : image->NotifyProgress(progress, invalidRect, frameCount,
57 68 : decoderFlags, surfaceFlags);
58 68 : }));
59 : }
60 :
61 : /* static */ void
62 33 : IDecodingTask::NotifyDecodeComplete(NotNull<RasterImage*> aImage,
63 : NotNull<Decoder*> aDecoder)
64 : {
65 33 : MOZ_ASSERT(aDecoder->HasError() || !aDecoder->InFrame(),
66 : "Decode complete in the middle of a frame?");
67 :
68 : // Capture the decoder's state.
69 33 : DecoderFinalStatus finalStatus = aDecoder->FinalStatus();
70 66 : ImageMetadata metadata = aDecoder->GetImageMetadata();
71 66 : DecoderTelemetry telemetry = aDecoder->Telemetry();
72 33 : Progress progress = aDecoder->TakeProgress();
73 33 : IntRect invalidRect = aDecoder->TakeInvalidRect();
74 66 : Maybe<uint32_t> frameCount = aDecoder->TakeCompleteFrameCount();
75 33 : DecoderFlags decoderFlags = aDecoder->GetDecoderFlags();
76 33 : SurfaceFlags surfaceFlags = aDecoder->GetSurfaceFlags();
77 :
78 : // Synchronously notify if we can.
79 33 : if (NS_IsMainThread() && !(decoderFlags & DecoderFlags::ASYNC_NOTIFY)) {
80 0 : aImage->NotifyDecodeComplete(finalStatus, metadata, telemetry, progress,
81 : invalidRect, frameCount, decoderFlags,
82 0 : surfaceFlags);
83 0 : return;
84 : }
85 :
86 : // We're forced to notify asynchronously.
87 66 : NotNull<RefPtr<RasterImage>> image = aImage;
88 66 : NS_DispatchToMainThread(NS_NewRunnableFunction(
89 : "IDecodingTask::NotifyDecodeComplete",
90 132 : [=]() -> void {
91 33 : image->NotifyDecodeComplete(finalStatus, metadata, telemetry, progress,
92 33 : invalidRect, frameCount, decoderFlags,
93 66 : surfaceFlags);
94 66 : }));
95 : }
96 :
97 :
98 : ///////////////////////////////////////////////////////////////////////////////
99 : // IDecodingTask implementation.
100 : ///////////////////////////////////////////////////////////////////////////////
101 :
102 : void
103 0 : IDecodingTask::Resume()
104 : {
105 0 : DecodePool::Singleton()->AsyncRun(this);
106 0 : }
107 :
108 :
109 : ///////////////////////////////////////////////////////////////////////////////
110 : // MetadataDecodingTask implementation.
111 : ///////////////////////////////////////////////////////////////////////////////
112 :
113 19 : MetadataDecodingTask::MetadataDecodingTask(NotNull<Decoder*> aDecoder)
114 : : mMutex("mozilla::image::MetadataDecodingTask")
115 19 : , mDecoder(aDecoder)
116 : {
117 19 : MOZ_ASSERT(mDecoder->IsMetadataDecode(),
118 : "Use DecodingTask for non-metadata decodes");
119 19 : }
120 :
121 : void
122 19 : MetadataDecodingTask::Run()
123 : {
124 38 : MutexAutoLock lock(mMutex);
125 :
126 38 : LexerResult result = mDecoder->Decode(WrapNotNull(this));
127 :
128 19 : if (result.is<TerminalState>()) {
129 19 : NotifyDecodeComplete(mDecoder->GetImage(), mDecoder);
130 19 : return; // We're done.
131 : }
132 :
133 0 : if (result == LexerResult(Yield::NEED_MORE_DATA)) {
134 : // We can't make any more progress right now. We also don't want to report
135 : // any progress, because it's important that metadata decode results are
136 : // delivered atomically. The decoder itself will ensure that we get
137 : // reenqueued when more data is available; just return for now.
138 0 : return;
139 : }
140 :
141 0 : MOZ_ASSERT_UNREACHABLE("Metadata decode yielded for an unexpected reason");
142 : }
143 :
144 :
145 : ///////////////////////////////////////////////////////////////////////////////
146 : // AnonymousDecodingTask implementation.
147 : ///////////////////////////////////////////////////////////////////////////////
148 :
149 0 : AnonymousDecodingTask::AnonymousDecodingTask(NotNull<Decoder*> aDecoder)
150 0 : : mDecoder(aDecoder)
151 0 : { }
152 :
153 : void
154 0 : AnonymousDecodingTask::Run()
155 : {
156 : while (true) {
157 0 : LexerResult result = mDecoder->Decode(WrapNotNull(this));
158 :
159 0 : if (result.is<TerminalState>()) {
160 0 : return; // We're done.
161 : }
162 :
163 0 : if (result == LexerResult(Yield::NEED_MORE_DATA)) {
164 : // We can't make any more progress right now. Let the caller decide how to
165 : // handle it.
166 0 : return;
167 : }
168 :
169 : // Right now we don't do anything special for other kinds of yields, so just
170 : // keep working.
171 0 : MOZ_ASSERT(result.is<Yield>());
172 0 : }
173 : }
174 :
175 : } // namespace image
176 : } // namespace mozilla
|