Flutter Engine
The Flutter Engine
SkJpegSegmentScan.cpp
Go to the documentation of this file.
1/*
2 * Copyright 2023 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
9
10#include "include/core/SkData.h"
15
16#include <cstring>
17#include <utility>
18
19////////////////////////////////////////////////////////////////////////////////////////////////////
20// SkJpegSegmentScanner
21
22SkJpegSegmentScanner::SkJpegSegmentScanner(uint8_t stopMarker) : fStopMarker(stopMarker) {}
23
24const std::vector<SkJpegSegment>& SkJpegSegmentScanner::getSegments() const { return fSegments; }
25
27 const SkJpegSegment& segment) {
28 return SkData::MakeSubset(
29 scannedData,
32}
33
34void SkJpegSegmentScanner::onBytes(const void* data, size_t size) {
35 const uint8_t* bytes = reinterpret_cast<const uint8_t*>(data);
36 size_t bytesRemaining = size;
37
38 while (bytesRemaining > 0) {
39 // Process the data byte-by-byte, unless we are in kSegmentParam or kEntropyCodedData, in
40 // which case, perform some optimizations to avoid examining every byte.
41 size_t bytesToMoveForward = 0;
42 switch (fState) {
43 case State::kSegmentParam: {
44 // Skip forward through payloads.
45 SkASSERT(fSegmentParamBytesRemaining > 0);
46 bytesToMoveForward = std::min(fSegmentParamBytesRemaining, bytesRemaining);
47 fSegmentParamBytesRemaining -= bytesToMoveForward;
48 if (fSegmentParamBytesRemaining == 0) {
49 fState = State::kEntropyCodedData;
50 }
51 break;
52 }
53 case State::kEntropyCodedData: {
54 // Skip through entropy-coded data, only looking at sentinel characters.
55 const uint8_t* sentinel =
56 reinterpret_cast<const uint8_t*>(memchr(bytes, 0xFF, bytesRemaining));
57 if (sentinel) {
58 bytesToMoveForward = (sentinel - bytes) + 1;
59 fState = State::kEntropyCodedDataSentinel;
60 } else {
61 bytesToMoveForward = bytesRemaining;
62 }
63 break;
64 }
65 case State::kDone:
66 // Skip all data after we have hit our stop marker.
67 bytesToMoveForward = bytesRemaining;
68 break;
69 default: {
70 onByte(*bytes);
71 bytesToMoveForward = 1;
72 break;
73 }
74 }
75 SkASSERT(bytesToMoveForward > 0);
76 fOffset += bytesToMoveForward;
77 bytes += bytesToMoveForward;
78 bytesRemaining -= bytesToMoveForward;
79 }
80}
81
82void SkJpegSegmentScanner::saveCurrentSegment(uint16_t length) {
83 SkJpegSegment s = {fCurrentSegmentOffset, fCurrentSegmentMarker, length};
84 fSegments.push_back(s);
85
86 fCurrentSegmentMarker = 0;
87 fCurrentSegmentOffset = 0;
88}
89
90void SkJpegSegmentScanner::onMarkerSecondByte(uint8_t byte) {
91 SkASSERT(fState == State::kStartOfImageByte1 || fState == State::kSecondMarkerByte1 ||
92 fState == State::kEntropyCodedDataSentinel ||
93 fState == State::kPostEntropyCodedDataFill);
94
95 fCurrentSegmentMarker = byte;
96 fCurrentSegmentOffset = fOffset - 1;
97
98 if (byte == fStopMarker) {
99 saveCurrentSegment(0);
100 fState = State::kDone;
101 } else if (byte == kJpegMarkerStartOfImage) {
102 saveCurrentSegment(0);
103 fState = State::kSecondMarkerByte0;
104 } else if (MarkerStandsAlone(byte)) {
105 saveCurrentSegment(0);
106 fState = State::kEntropyCodedData;
107 } else {
108 fCurrentSegmentMarker = byte;
109 fState = State::kSegmentParamLengthByte0;
110 }
111}
112
113void SkJpegSegmentScanner::onByte(uint8_t byte) {
114 switch (fState) {
115 case State::kStartOfImageByte0:
116 if (byte != 0xFF) {
117 SkCodecPrintf("First byte was %02x, not 0xFF", byte);
118 fState = State::kError;
119 return;
120 }
121 fState = State::kStartOfImageByte1;
122 break;
123 case State::kStartOfImageByte1:
124 if (byte != kJpegMarkerStartOfImage) {
125 SkCodecPrintf("Second byte was %02x, not %02x", byte, kJpegMarkerStartOfImage);
126 fState = State::kError;
127 return;
128 }
129 onMarkerSecondByte(byte);
130 break;
131 case State::kSecondMarkerByte0:
132 if (byte != 0xFF) {
133 SkCodecPrintf("Third byte was %02x, not 0xFF", byte);
134 fState = State::kError;
135 return;
136 }
137 fState = State::kSecondMarkerByte1;
138 break;
139 case State::kSecondMarkerByte1:
140 // See section B.1.1.3: All markers are assigned two-byte codes: a 0xFF byte followed by
141 // a byte which is not equal to 0x00 or 0xFF.
142 if (byte == 0xFF || byte == 0x00) {
143 SkCodecPrintf("SkJpegSegment marker was 0xFF,0xFF or 0xFF,0x00");
144 fState = State::kError;
145 return;
146 }
147 onMarkerSecondByte(byte);
148 break;
149 case State::kSegmentParamLengthByte0:
150 fSegmentParamLengthByte0 = byte;
151 fState = State::kSegmentParamLengthByte1;
152 break;
153 case State::kSegmentParamLengthByte1: {
154 uint16_t paramLength = 256u * fSegmentParamLengthByte0 + byte;
155 fSegmentParamLengthByte0 = 0;
156
157 // See section B.1.1.4: A marker segment consists of a marker followed by a sequence
158 // of related parameters. The first parameter in a marker segment is the two-byte length
159 // parameter. This length parameter encodes the number of bytes in the marker segment,
160 // including the length parameter and excluding the two-byte marker.
161 if (paramLength < kJpegSegmentParameterLengthSize) {
162 SkCodecPrintf("SkJpegSegment payload length was %u < 2 bytes", paramLength);
163 fState = State::kError;
164 return;
165 }
166 saveCurrentSegment(paramLength);
167 fSegmentParamBytesRemaining = paramLength - kJpegSegmentParameterLengthSize;
168 if (fSegmentParamBytesRemaining > 0) {
169 fState = State::kSegmentParam;
170 } else {
171 fState = State::kEntropyCodedData;
172 }
173 break;
174 }
175 case State::kSegmentParam:
176 SkASSERT(fSegmentParamBytesRemaining > 0);
177 fSegmentParamBytesRemaining -= 1;
178 if (fSegmentParamBytesRemaining == 0) {
179 fState = State::kEntropyCodedData;
180 }
181 break;
182 case State::kEntropyCodedData:
183 if (byte == 0xFF) {
184 fState = State::kEntropyCodedDataSentinel;
185 }
186 break;
187 case State::kEntropyCodedDataSentinel:
188 if (byte == 0x00) {
189 fState = State::kEntropyCodedData;
190 } else if (byte == 0xFF) {
191 fState = State::kPostEntropyCodedDataFill;
192 } else {
193 onMarkerSecondByte(byte);
194 }
195 break;
196 case State::kPostEntropyCodedDataFill:
197 // See section B.1.1.3: Any marker may optionally be preceded by any number of fill
198 // bytes, which are bytes assigned code 0xFF. Skip past any 0xFF fill bytes that may be
199 // present at the end of the entropy-coded data.
200 if (byte == 0xFF) {
201 fState = State::kPostEntropyCodedDataFill;
202 } else if (byte == 0x00) {
203 SkCodecPrintf("Post entropy coded data had 0xFF,0x00");
204 fState = State::kError;
205 return;
206 } else {
207 onMarkerSecondByte(byte);
208 }
209 break;
210 case State::kDone:
211 break;
212 case State::kError:
213 break;
214 }
215}
#define SkASSERT(cond)
Definition: SkAssert.h:116
#define SkCodecPrintf(...)
Definition: SkCodecPriv.h:23
static constexpr uint8_t kJpegMarkerStartOfImage
static constexpr size_t kJpegSegmentParameterLengthSize
static constexpr size_t kJpegMarkerCodeSize
Definition: SkData.h:25
static sk_sp< SkData > MakeSubset(const SkData *src, size_t offset, size_t length)
Definition: SkData.cpp:173
const std::vector< SkJpegSegment > & getSegments() const
static sk_sp< SkData > GetParameters(const SkData *scannedData, const SkJpegSegment &segment)
SkJpegSegmentScanner(uint8_t stopMarker=kJpegMarkerEndOfImage)
void onBytes(const void *data, size_t size)
struct MyStruct s
static float min(float r, float g, float b)
Definition: hsl.cpp:48
size_t length
it will be possible to load the file into Perfetto s trace viewer disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font Indicates whether the embedding started a prefetch of the default font manager before creating the engine run In non interactive keep the shell running after the Dart script has completed enable serial On low power devices with low core running concurrent GC tasks on threads can cause them to contend with the UI thread which could potentially lead to jank This option turns off all concurrent GC activities domain network JSON encoded network policy per domain This overrides the DisallowInsecureConnections switch Embedder can specify whether to allow or disallow insecure connections at a domain level old gen heap size
Definition: switches.h:259
uint16_t parameterLength
std::shared_ptr< const fml::Mapping > data
Definition: texture_gles.cc:63