Line data Source code
1 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 : *
3 : * This Source Code Form is subject to the terms of the Mozilla Public
4 : * License, v. 2.0. If a copy of the MPL was not distributed with this
5 : * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 :
7 : #include "ImageLogging.h" // Must appear first.
8 :
9 : #include "nsJPEGDecoder.h"
10 :
11 : #include <cstdint>
12 :
13 : #include "imgFrame.h"
14 : #include "Orientation.h"
15 : #include "EXIF.h"
16 :
17 : #include "nsIInputStream.h"
18 :
19 : #include "nspr.h"
20 : #include "nsCRT.h"
21 : #include "gfxColor.h"
22 :
23 : #include "jerror.h"
24 :
25 : #include "gfxPlatform.h"
26 : #include "mozilla/EndianUtils.h"
27 : #include "mozilla/Telemetry.h"
28 :
29 : extern "C" {
30 : #include "iccjpeg.h"
31 : }
32 :
33 : #if MOZ_BIG_ENDIAN
34 : #define MOZ_JCS_EXT_NATIVE_ENDIAN_XRGB JCS_EXT_XRGB
35 : #else
36 : #define MOZ_JCS_EXT_NATIVE_ENDIAN_XRGB JCS_EXT_BGRX
37 : #endif
38 :
39 : static void cmyk_convert_rgb(JSAMPROW row, JDIMENSION width);
40 :
41 : namespace mozilla {
42 : namespace image {
43 :
44 : static mozilla::LazyLogModule sJPEGLog("JPEGDecoder");
45 :
46 : static mozilla::LazyLogModule sJPEGDecoderAccountingLog("JPEGDecoderAccounting");
47 :
48 : static qcms_profile*
49 0 : GetICCProfile(struct jpeg_decompress_struct& info)
50 : {
51 : JOCTET* profilebuf;
52 : uint32_t profileLength;
53 0 : qcms_profile* profile = nullptr;
54 :
55 0 : if (read_icc_profile(&info, &profilebuf, &profileLength)) {
56 0 : profile = qcms_profile_from_memory(profilebuf, profileLength);
57 0 : free(profilebuf);
58 : }
59 :
60 0 : return profile;
61 : }
62 :
63 : METHODDEF(void) init_source (j_decompress_ptr jd);
64 : METHODDEF(boolean) fill_input_buffer (j_decompress_ptr jd);
65 : METHODDEF(void) skip_input_data (j_decompress_ptr jd, long num_bytes);
66 : METHODDEF(void) term_source (j_decompress_ptr jd);
67 : METHODDEF(void) my_error_exit (j_common_ptr cinfo);
68 :
69 : // Normal JFIF markers can't have more bytes than this.
70 : #define MAX_JPEG_MARKER_LENGTH (((uint32_t)1 << 16) - 1)
71 :
72 0 : nsJPEGDecoder::nsJPEGDecoder(RasterImage* aImage,
73 0 : Decoder::DecodeStyle aDecodeStyle)
74 : : Decoder(aImage)
75 0 : , mLexer(Transition::ToUnbuffered(State::FINISHED_JPEG_DATA,
76 : State::JPEG_DATA,
77 : SIZE_MAX),
78 : Transition::TerminateSuccess())
79 0 : , mDecodeStyle(aDecodeStyle)
80 : {
81 0 : mState = JPEG_HEADER;
82 0 : mReading = true;
83 0 : mImageData = nullptr;
84 :
85 0 : mBytesToSkip = 0;
86 0 : memset(&mInfo, 0, sizeof(jpeg_decompress_struct));
87 0 : memset(&mSourceMgr, 0, sizeof(mSourceMgr));
88 0 : mInfo.client_data = (void*)this;
89 :
90 0 : mSegment = nullptr;
91 0 : mSegmentLen = 0;
92 :
93 0 : mBackBuffer = nullptr;
94 0 : mBackBufferLen = mBackBufferSize = mBackBufferUnreadLen = 0;
95 :
96 0 : mInProfile = nullptr;
97 0 : mTransform = nullptr;
98 :
99 0 : mCMSMode = 0;
100 :
101 0 : MOZ_LOG(sJPEGDecoderAccountingLog, LogLevel::Debug,
102 : ("nsJPEGDecoder::nsJPEGDecoder: Creating JPEG decoder %p",
103 : this));
104 0 : }
105 :
106 0 : nsJPEGDecoder::~nsJPEGDecoder()
107 : {
108 : // Step 8: Release JPEG decompression object
109 0 : mInfo.src = nullptr;
110 0 : jpeg_destroy_decompress(&mInfo);
111 :
112 0 : free(mBackBuffer);
113 0 : mBackBuffer = nullptr;
114 0 : if (mTransform) {
115 0 : qcms_transform_release(mTransform);
116 : }
117 0 : if (mInProfile) {
118 0 : qcms_profile_release(mInProfile);
119 : }
120 :
121 0 : MOZ_LOG(sJPEGDecoderAccountingLog, LogLevel::Debug,
122 : ("nsJPEGDecoder::~nsJPEGDecoder: Destroying JPEG decoder %p",
123 : this));
124 0 : }
125 :
126 : Maybe<Telemetry::HistogramID>
127 0 : nsJPEGDecoder::SpeedHistogram() const
128 : {
129 0 : return Some(Telemetry::IMAGE_DECODE_SPEED_JPEG);
130 : }
131 :
132 : nsresult
133 0 : nsJPEGDecoder::InitInternal()
134 : {
135 0 : mCMSMode = gfxPlatform::GetCMSMode();
136 0 : if (GetSurfaceFlags() & SurfaceFlags::NO_COLORSPACE_CONVERSION) {
137 0 : mCMSMode = eCMSMode_Off;
138 : }
139 :
140 : // We set up the normal JPEG error routines, then override error_exit.
141 0 : mInfo.err = jpeg_std_error(&mErr.pub);
142 : // mInfo.err = jpeg_std_error(&mErr.pub);
143 0 : mErr.pub.error_exit = my_error_exit;
144 : // Establish the setjmp return context for my_error_exit to use.
145 0 : if (setjmp(mErr.setjmp_buffer)) {
146 : // If we get here, the JPEG code has signaled an error, and initialization
147 : // has failed.
148 0 : return NS_ERROR_FAILURE;
149 : }
150 :
151 : // Step 1: allocate and initialize JPEG decompression object
152 0 : jpeg_create_decompress(&mInfo);
153 : // Set the source manager
154 0 : mInfo.src = &mSourceMgr;
155 :
156 : // Step 2: specify data source (eg, a file)
157 :
158 : // Setup callback functions.
159 0 : mSourceMgr.init_source = init_source;
160 0 : mSourceMgr.fill_input_buffer = fill_input_buffer;
161 0 : mSourceMgr.skip_input_data = skip_input_data;
162 0 : mSourceMgr.resync_to_restart = jpeg_resync_to_restart;
163 0 : mSourceMgr.term_source = term_source;
164 :
165 : // Record app markers for ICC data
166 0 : for (uint32_t m = 0; m < 16; m++) {
167 0 : jpeg_save_markers(&mInfo, JPEG_APP0 + m, 0xFFFF);
168 : }
169 :
170 0 : return NS_OK;
171 : }
172 :
173 : nsresult
174 0 : nsJPEGDecoder::FinishInternal()
175 : {
176 : // If we're not in any sort of error case, force our state to JPEG_DONE.
177 0 : if ((mState != JPEG_DONE && mState != JPEG_SINK_NON_JPEG_TRAILER) &&
178 0 : (mState != JPEG_ERROR) &&
179 0 : !IsMetadataDecode()) {
180 0 : mState = JPEG_DONE;
181 : }
182 :
183 0 : return NS_OK;
184 : }
185 :
186 : LexerResult
187 0 : nsJPEGDecoder::DoDecode(SourceBufferIterator& aIterator, IResumable* aOnResume)
188 : {
189 0 : MOZ_ASSERT(!HasError(), "Shouldn't call DoDecode after error!");
190 :
191 : return mLexer.Lex(aIterator, aOnResume,
192 0 : [=](State aState, const char* aData, size_t aLength) {
193 0 : switch (aState) {
194 : case State::JPEG_DATA:
195 0 : return ReadJPEGData(aData, aLength);
196 : case State::FINISHED_JPEG_DATA:
197 0 : return FinishedJPEGData();
198 : }
199 0 : MOZ_CRASH("Unknown State");
200 0 : });
201 : }
202 :
203 : LexerTransition<nsJPEGDecoder::State>
204 0 : nsJPEGDecoder::ReadJPEGData(const char* aData, size_t aLength)
205 : {
206 0 : mSegment = reinterpret_cast<const JOCTET*>(aData);
207 0 : mSegmentLen = aLength;
208 :
209 : // Return here if there is a fatal error within libjpeg.
210 : nsresult error_code;
211 : // This cast to nsresult makes sense because setjmp() returns whatever we
212 : // passed to longjmp(), which was actually an nsresult.
213 0 : if ((error_code = static_cast<nsresult>(setjmp(mErr.setjmp_buffer))) != NS_OK) {
214 0 : if (error_code == NS_ERROR_FAILURE) {
215 : // Error due to corrupt data. Make sure that we don't feed any more data
216 : // to libjpeg-turbo.
217 0 : mState = JPEG_SINK_NON_JPEG_TRAILER;
218 0 : MOZ_LOG(sJPEGDecoderAccountingLog, LogLevel::Debug,
219 : ("} (setjmp returned NS_ERROR_FAILURE)"));
220 : } else {
221 : // Error for another reason. (Possibly OOM.)
222 0 : mState = JPEG_ERROR;
223 0 : MOZ_LOG(sJPEGDecoderAccountingLog, LogLevel::Debug,
224 : ("} (setjmp returned an error)"));
225 : }
226 :
227 0 : return Transition::TerminateFailure();
228 : }
229 :
230 0 : MOZ_LOG(sJPEGLog, LogLevel::Debug,
231 : ("[this=%p] nsJPEGDecoder::Write -- processing JPEG data\n", this));
232 :
233 0 : switch (mState) {
234 : case JPEG_HEADER: {
235 0 : LOG_SCOPE((mozilla::LogModule*)sJPEGLog, "nsJPEGDecoder::Write -- entering JPEG_HEADER"
236 : " case");
237 :
238 : // Step 3: read file parameters with jpeg_read_header()
239 0 : if (jpeg_read_header(&mInfo, TRUE) == JPEG_SUSPENDED) {
240 0 : MOZ_LOG(sJPEGDecoderAccountingLog, LogLevel::Debug,
241 : ("} (JPEG_SUSPENDED)"));
242 0 : return Transition::ContinueUnbuffered(State::JPEG_DATA); // I/O suspension
243 : }
244 :
245 : // Post our size to the superclass
246 0 : PostSize(mInfo.image_width, mInfo.image_height,
247 0 : ReadOrientationFromEXIF());
248 0 : if (HasError()) {
249 : // Setting the size led to an error.
250 0 : mState = JPEG_ERROR;
251 0 : return Transition::TerminateFailure();
252 : }
253 :
254 : // If we're doing a metadata decode, we're done.
255 0 : if (IsMetadataDecode()) {
256 0 : return Transition::TerminateSuccess();
257 : }
258 :
259 : // We're doing a full decode.
260 0 : if (mCMSMode != eCMSMode_Off &&
261 0 : (mInProfile = GetICCProfile(mInfo)) != nullptr) {
262 0 : uint32_t profileSpace = qcms_profile_get_color_space(mInProfile);
263 0 : bool mismatch = false;
264 :
265 : #ifdef DEBUG_tor
266 : fprintf(stderr, "JPEG profileSpace: 0x%08X\n", profileSpace);
267 : #endif
268 0 : switch (mInfo.jpeg_color_space) {
269 : case JCS_GRAYSCALE:
270 0 : if (profileSpace == icSigRgbData) {
271 0 : mInfo.out_color_space = JCS_RGB;
272 0 : } else if (profileSpace != icSigGrayData) {
273 0 : mismatch = true;
274 : }
275 0 : break;
276 : case JCS_RGB:
277 0 : if (profileSpace != icSigRgbData) {
278 0 : mismatch = true;
279 : }
280 0 : break;
281 : case JCS_YCbCr:
282 0 : if (profileSpace == icSigRgbData) {
283 0 : mInfo.out_color_space = JCS_RGB;
284 : } else {
285 : // qcms doesn't support ycbcr
286 0 : mismatch = true;
287 : }
288 0 : break;
289 : case JCS_CMYK:
290 : case JCS_YCCK:
291 : // qcms doesn't support cmyk
292 0 : mismatch = true;
293 0 : break;
294 : default:
295 0 : mState = JPEG_ERROR;
296 0 : MOZ_LOG(sJPEGDecoderAccountingLog, LogLevel::Debug,
297 : ("} (unknown colorpsace (1))"));
298 0 : return Transition::TerminateFailure();
299 : }
300 :
301 0 : if (!mismatch) {
302 : qcms_data_type type;
303 0 : switch (mInfo.out_color_space) {
304 : case JCS_GRAYSCALE:
305 0 : type = QCMS_DATA_GRAY_8;
306 0 : break;
307 : case JCS_RGB:
308 0 : type = QCMS_DATA_RGB_8;
309 0 : break;
310 : default:
311 0 : mState = JPEG_ERROR;
312 0 : MOZ_LOG(sJPEGDecoderAccountingLog, LogLevel::Debug,
313 : ("} (unknown colorpsace (2))"));
314 0 : return Transition::TerminateFailure();
315 : }
316 : #if 0
317 : // We don't currently support CMYK profiles. The following
318 : // code dealt with lcms types. Add something like this
319 : // back when we gain support for CMYK.
320 :
321 : // Adobe Photoshop writes YCCK/CMYK files with inverted data
322 : if (mInfo.out_color_space == JCS_CMYK) {
323 : type |= FLAVOR_SH(mInfo.saw_Adobe_marker ? 1 : 0);
324 : }
325 : #endif
326 :
327 0 : if (gfxPlatform::GetCMSOutputProfile()) {
328 :
329 : // Calculate rendering intent.
330 0 : int intent = gfxPlatform::GetRenderingIntent();
331 0 : if (intent == -1) {
332 0 : intent = qcms_profile_get_rendering_intent(mInProfile);
333 : }
334 :
335 : // Create the color management transform.
336 0 : mTransform = qcms_transform_create(mInProfile,
337 : type,
338 : gfxPlatform::GetCMSOutputProfile(),
339 : QCMS_DATA_RGB_8,
340 : (qcms_intent)intent);
341 : }
342 : } else {
343 : #ifdef DEBUG_tor
344 : fprintf(stderr, "ICM profile colorspace mismatch\n");
345 : #endif
346 : }
347 : }
348 :
349 0 : if (!mTransform) {
350 0 : switch (mInfo.jpeg_color_space) {
351 : case JCS_GRAYSCALE:
352 : case JCS_RGB:
353 : case JCS_YCbCr:
354 : // if we're not color managing we can decode directly to
355 : // MOZ_JCS_EXT_NATIVE_ENDIAN_XRGB
356 0 : if (mCMSMode != eCMSMode_All) {
357 0 : mInfo.out_color_space = MOZ_JCS_EXT_NATIVE_ENDIAN_XRGB;
358 0 : mInfo.out_color_components = 4;
359 : } else {
360 0 : mInfo.out_color_space = JCS_RGB;
361 : }
362 0 : break;
363 : case JCS_CMYK:
364 : case JCS_YCCK:
365 : // libjpeg can convert from YCCK to CMYK, but not to RGB
366 0 : mInfo.out_color_space = JCS_CMYK;
367 0 : break;
368 : default:
369 0 : mState = JPEG_ERROR;
370 0 : MOZ_LOG(sJPEGDecoderAccountingLog, LogLevel::Debug,
371 : ("} (unknown colorpsace (3))"));
372 0 : return Transition::TerminateFailure();
373 : }
374 : }
375 :
376 : // Don't allocate a giant and superfluous memory buffer
377 : // when not doing a progressive decode.
378 0 : mInfo.buffered_image = mDecodeStyle == PROGRESSIVE &&
379 0 : jpeg_has_multiple_scans(&mInfo);
380 :
381 : /* Used to set up image size so arrays can be allocated */
382 0 : jpeg_calc_output_dimensions(&mInfo);
383 :
384 0 : MOZ_ASSERT(!mImageData, "Already have a buffer allocated?");
385 0 : nsresult rv = AllocateFrame(/* aFrameNum = */ 0, OutputSize(),
386 0 : FullOutputFrame(), SurfaceFormat::B8G8R8X8);
387 0 : if (NS_FAILED(rv)) {
388 0 : mState = JPEG_ERROR;
389 0 : MOZ_LOG(sJPEGDecoderAccountingLog, LogLevel::Debug,
390 : ("} (could not initialize image frame)"));
391 0 : return Transition::TerminateFailure();
392 : }
393 :
394 0 : MOZ_ASSERT(mImageData, "Should have a buffer now");
395 :
396 0 : if (mDownscaler) {
397 0 : nsresult rv = mDownscaler->BeginFrame(Size(), Nothing(),
398 : mImageData,
399 0 : /* aHasAlpha = */ false);
400 0 : if (NS_FAILED(rv)) {
401 0 : mState = JPEG_ERROR;
402 0 : return Transition::TerminateFailure();
403 : }
404 : }
405 :
406 0 : MOZ_LOG(sJPEGDecoderAccountingLog, LogLevel::Debug,
407 : (" JPEGDecoderAccounting: nsJPEGDecoder::"
408 : "Write -- created image frame with %ux%u pixels",
409 : mInfo.image_width, mInfo.image_height));
410 :
411 0 : mState = JPEG_START_DECOMPRESS;
412 : MOZ_FALLTHROUGH; // to start decompressing.
413 : }
414 :
415 : case JPEG_START_DECOMPRESS: {
416 0 : LOG_SCOPE((mozilla::LogModule*)sJPEGLog, "nsJPEGDecoder::Write -- entering"
417 : " JPEG_START_DECOMPRESS case");
418 : // Step 4: set parameters for decompression
419 :
420 : // FIXME -- Should reset dct_method and dither mode
421 : // for final pass of progressive JPEG
422 :
423 0 : mInfo.dct_method = JDCT_ISLOW;
424 0 : mInfo.dither_mode = JDITHER_FS;
425 0 : mInfo.do_fancy_upsampling = TRUE;
426 0 : mInfo.enable_2pass_quant = FALSE;
427 0 : mInfo.do_block_smoothing = TRUE;
428 :
429 : // Step 5: Start decompressor
430 0 : if (jpeg_start_decompress(&mInfo) == FALSE) {
431 0 : MOZ_LOG(sJPEGDecoderAccountingLog, LogLevel::Debug,
432 : ("} (I/O suspension after jpeg_start_decompress())"));
433 0 : return Transition::ContinueUnbuffered(State::JPEG_DATA); // I/O suspension
434 : }
435 :
436 : // If this is a progressive JPEG ...
437 0 : mState = mInfo.buffered_image ?
438 : JPEG_DECOMPRESS_PROGRESSIVE : JPEG_DECOMPRESS_SEQUENTIAL;
439 : MOZ_FALLTHROUGH; // to decompress sequential JPEG.
440 : }
441 :
442 : case JPEG_DECOMPRESS_SEQUENTIAL: {
443 0 : if (mState == JPEG_DECOMPRESS_SEQUENTIAL) {
444 0 : LOG_SCOPE((mozilla::LogModule*)sJPEGLog, "nsJPEGDecoder::Write -- "
445 : "JPEG_DECOMPRESS_SEQUENTIAL case");
446 :
447 : bool suspend;
448 0 : OutputScanlines(&suspend);
449 :
450 0 : if (suspend) {
451 0 : MOZ_LOG(sJPEGDecoderAccountingLog, LogLevel::Debug,
452 : ("} (I/O suspension after OutputScanlines() - SEQUENTIAL)"));
453 0 : return Transition::ContinueUnbuffered(State::JPEG_DATA); // I/O suspension
454 : }
455 :
456 : // If we've completed image output ...
457 0 : NS_ASSERTION(mInfo.output_scanline == mInfo.output_height,
458 : "We didn't process all of the data!");
459 0 : mState = JPEG_DONE;
460 : }
461 : MOZ_FALLTHROUGH; // to decompress progressive JPEG.
462 : }
463 :
464 : case JPEG_DECOMPRESS_PROGRESSIVE: {
465 0 : if (mState == JPEG_DECOMPRESS_PROGRESSIVE) {
466 0 : LOG_SCOPE((mozilla::LogModule*)sJPEGLog,
467 : "nsJPEGDecoder::Write -- JPEG_DECOMPRESS_PROGRESSIVE case");
468 :
469 : int status;
470 0 : do {
471 0 : status = jpeg_consume_input(&mInfo);
472 0 : } while ((status != JPEG_SUSPENDED) &&
473 : (status != JPEG_REACHED_EOI));
474 :
475 : for (;;) {
476 0 : if (mInfo.output_scanline == 0) {
477 0 : int scan = mInfo.input_scan_number;
478 :
479 : // if we haven't displayed anything yet (output_scan_number==0)
480 : // and we have enough data for a complete scan, force output
481 : // of the last full scan
482 0 : if ((mInfo.output_scan_number == 0) &&
483 0 : (scan > 1) &&
484 : (status != JPEG_REACHED_EOI))
485 0 : scan--;
486 :
487 0 : if (!jpeg_start_output(&mInfo, scan)) {
488 0 : MOZ_LOG(sJPEGDecoderAccountingLog, LogLevel::Debug,
489 : ("} (I/O suspension after jpeg_start_output() -"
490 : " PROGRESSIVE)"));
491 0 : return Transition::ContinueUnbuffered(State::JPEG_DATA); // I/O suspension
492 : }
493 : }
494 :
495 0 : if (mInfo.output_scanline == 0xffffff) {
496 0 : mInfo.output_scanline = 0;
497 : }
498 :
499 : bool suspend;
500 0 : OutputScanlines(&suspend);
501 :
502 0 : if (suspend) {
503 0 : if (mInfo.output_scanline == 0) {
504 : // didn't manage to read any lines - flag so we don't call
505 : // jpeg_start_output() multiple times for the same scan
506 0 : mInfo.output_scanline = 0xffffff;
507 : }
508 0 : MOZ_LOG(sJPEGDecoderAccountingLog, LogLevel::Debug,
509 : ("} (I/O suspension after OutputScanlines() - PROGRESSIVE)"));
510 0 : return Transition::ContinueUnbuffered(State::JPEG_DATA); // I/O suspension
511 : }
512 :
513 0 : if (mInfo.output_scanline == mInfo.output_height) {
514 0 : if (!jpeg_finish_output(&mInfo)) {
515 0 : MOZ_LOG(sJPEGDecoderAccountingLog, LogLevel::Debug,
516 : ("} (I/O suspension after jpeg_finish_output() -"
517 : " PROGRESSIVE)"));
518 0 : return Transition::ContinueUnbuffered(State::JPEG_DATA); // I/O suspension
519 : }
520 :
521 0 : if (jpeg_input_complete(&mInfo) &&
522 0 : (mInfo.input_scan_number == mInfo.output_scan_number))
523 0 : break;
524 :
525 0 : mInfo.output_scanline = 0;
526 0 : if (mDownscaler) {
527 0 : mDownscaler->ResetForNextProgressivePass();
528 : }
529 : }
530 0 : }
531 :
532 0 : mState = JPEG_DONE;
533 : }
534 : MOZ_FALLTHROUGH; // to finish decompressing.
535 : }
536 :
537 : case JPEG_DONE: {
538 0 : LOG_SCOPE((mozilla::LogModule*)sJPEGLog, "nsJPEGDecoder::ProcessData -- entering"
539 : " JPEG_DONE case");
540 :
541 : // Step 7: Finish decompression
542 :
543 0 : if (jpeg_finish_decompress(&mInfo) == FALSE) {
544 0 : MOZ_LOG(sJPEGDecoderAccountingLog, LogLevel::Debug,
545 : ("} (I/O suspension after jpeg_finish_decompress() - DONE)"));
546 0 : return Transition::ContinueUnbuffered(State::JPEG_DATA); // I/O suspension
547 : }
548 :
549 : // Make sure we don't feed any more data to libjpeg-turbo.
550 0 : mState = JPEG_SINK_NON_JPEG_TRAILER;
551 :
552 : // We're done.
553 0 : return Transition::TerminateSuccess();
554 : }
555 : case JPEG_SINK_NON_JPEG_TRAILER:
556 0 : MOZ_LOG(sJPEGLog, LogLevel::Debug,
557 : ("[this=%p] nsJPEGDecoder::ProcessData -- entering"
558 : " JPEG_SINK_NON_JPEG_TRAILER case\n", this));
559 :
560 0 : MOZ_ASSERT_UNREACHABLE("Should stop getting data after entering state "
561 : "JPEG_SINK_NON_JPEG_TRAILER");
562 :
563 : return Transition::TerminateSuccess();
564 :
565 : case JPEG_ERROR:
566 0 : MOZ_ASSERT_UNREACHABLE("Should stop getting data after entering state "
567 : "JPEG_ERROR");
568 :
569 : return Transition::TerminateFailure();
570 : }
571 :
572 0 : MOZ_ASSERT_UNREACHABLE("Escaped the JPEG decoder state machine");
573 : return Transition::TerminateFailure();
574 : }
575 :
576 : LexerTransition<nsJPEGDecoder::State>
577 0 : nsJPEGDecoder::FinishedJPEGData()
578 : {
579 : // Since we set up an unbuffered read for SIZE_MAX bytes, if we actually read
580 : // all that data something is really wrong.
581 0 : MOZ_ASSERT_UNREACHABLE("Read the entire address space?");
582 : return Transition::TerminateFailure();
583 : }
584 :
585 : Orientation
586 0 : nsJPEGDecoder::ReadOrientationFromEXIF()
587 : {
588 : jpeg_saved_marker_ptr marker;
589 :
590 : // Locate the APP1 marker, where EXIF data is stored, in the marker list.
591 0 : for (marker = mInfo.marker_list ; marker != nullptr ; marker = marker->next) {
592 0 : if (marker->marker == JPEG_APP0 + 1) {
593 0 : break;
594 : }
595 : }
596 :
597 : // If we're at the end of the list, there's no EXIF data.
598 0 : if (!marker) {
599 0 : return Orientation();
600 : }
601 :
602 : // Extract the orientation information.
603 0 : EXIFData exif = EXIFParser::Parse(marker->data,
604 0 : static_cast<uint32_t>(marker->data_length));
605 0 : return exif.orientation;
606 : }
607 :
608 : void
609 0 : nsJPEGDecoder::NotifyDone()
610 : {
611 0 : PostFrameStop(Opacity::FULLY_OPAQUE);
612 0 : PostDecodeDone();
613 0 : }
614 :
615 : void
616 0 : nsJPEGDecoder::OutputScanlines(bool* suspend)
617 : {
618 0 : *suspend = false;
619 :
620 0 : const uint32_t top = mInfo.output_scanline;
621 :
622 0 : while ((mInfo.output_scanline < mInfo.output_height)) {
623 0 : uint32_t* imageRow = nullptr;
624 0 : if (mDownscaler) {
625 0 : imageRow = reinterpret_cast<uint32_t*>(mDownscaler->RowBuffer());
626 : } else {
627 0 : imageRow = reinterpret_cast<uint32_t*>(mImageData) +
628 0 : (mInfo.output_scanline * mInfo.output_width);
629 : }
630 :
631 0 : MOZ_ASSERT(imageRow, "Should have a row buffer here");
632 :
633 0 : if (mInfo.out_color_space == MOZ_JCS_EXT_NATIVE_ENDIAN_XRGB) {
634 : // Special case: scanline will be directly converted into packed ARGB
635 0 : if (jpeg_read_scanlines(&mInfo, (JSAMPARRAY)&imageRow, 1) != 1) {
636 0 : *suspend = true; // suspend
637 0 : break;
638 : }
639 0 : if (mDownscaler) {
640 0 : mDownscaler->CommitRow();
641 : }
642 0 : continue; // all done for this row!
643 : }
644 :
645 0 : JSAMPROW sampleRow = (JSAMPROW)imageRow;
646 0 : if (mInfo.output_components == 3) {
647 : // Put the pixels at end of row to enable in-place expansion
648 0 : sampleRow += mInfo.output_width;
649 : }
650 :
651 : // Request one scanline. Returns 0 or 1 scanlines.
652 0 : if (jpeg_read_scanlines(&mInfo, &sampleRow, 1) != 1) {
653 0 : *suspend = true; // suspend
654 0 : break;
655 : }
656 :
657 0 : if (mTransform) {
658 0 : JSAMPROW source = sampleRow;
659 0 : if (mInfo.out_color_space == JCS_GRAYSCALE) {
660 : // Convert from the 1byte grey pixels at begin of row
661 : // to the 3byte RGB byte pixels at 'end' of row
662 0 : sampleRow += mInfo.output_width;
663 : }
664 0 : qcms_transform_data(mTransform, source, sampleRow, mInfo.output_width);
665 : // Move 3byte RGB data to end of row
666 0 : if (mInfo.out_color_space == JCS_CMYK) {
667 0 : memmove(sampleRow + mInfo.output_width,
668 : sampleRow,
669 0 : 3 * mInfo.output_width);
670 0 : sampleRow += mInfo.output_width;
671 : }
672 : } else {
673 0 : if (mInfo.out_color_space == JCS_CMYK) {
674 : // Convert from CMYK to RGB
675 : // We cannot convert directly to Cairo, as the CMSRGBTransform
676 : // may wants to do a RGB transform...
677 : // Would be better to have platform CMSenabled transformation
678 : // from CMYK to (A)RGB...
679 0 : cmyk_convert_rgb((JSAMPROW)imageRow, mInfo.output_width);
680 0 : sampleRow += mInfo.output_width;
681 : }
682 0 : if (mCMSMode == eCMSMode_All) {
683 : // No embedded ICC profile - treat as sRGB
684 0 : qcms_transform* transform = gfxPlatform::GetCMSRGBTransform();
685 0 : if (transform) {
686 0 : qcms_transform_data(transform, sampleRow, sampleRow,
687 0 : mInfo.output_width);
688 : }
689 : }
690 : }
691 :
692 : // counter for while() loops below
693 0 : uint32_t idx = mInfo.output_width;
694 :
695 : // copy as bytes until source pointer is 32-bit-aligned
696 0 : for (; (NS_PTR_TO_UINT32(sampleRow) & 0x3) && idx; --idx) {
697 0 : *imageRow++ = gfxPackedPixel(0xFF, sampleRow[0], sampleRow[1],
698 0 : sampleRow[2]);
699 0 : sampleRow += 3;
700 : }
701 :
702 : // copy pixels in blocks of 4
703 0 : while (idx >= 4) {
704 0 : GFX_BLOCK_RGB_TO_FRGB(sampleRow, imageRow);
705 0 : idx -= 4;
706 0 : sampleRow += 12;
707 0 : imageRow += 4;
708 : }
709 :
710 : // copy remaining pixel(s)
711 0 : while (idx--) {
712 : // 32-bit read of final pixel will exceed buffer, so read bytes
713 0 : *imageRow++ = gfxPackedPixel(0xFF, sampleRow[0], sampleRow[1],
714 0 : sampleRow[2]);
715 0 : sampleRow += 3;
716 : }
717 :
718 0 : if (mDownscaler) {
719 0 : mDownscaler->CommitRow();
720 : }
721 : }
722 :
723 0 : if (mDownscaler && mDownscaler->HasInvalidation()) {
724 0 : DownscalerInvalidRect invalidRect = mDownscaler->TakeInvalidRect();
725 0 : PostInvalidation(invalidRect.mOriginalSizeRect,
726 0 : Some(invalidRect.mTargetSizeRect));
727 0 : MOZ_ASSERT(!mDownscaler->HasInvalidation());
728 0 : } else if (!mDownscaler && top != mInfo.output_scanline) {
729 0 : PostInvalidation(nsIntRect(0, top,
730 : mInfo.output_width,
731 0 : mInfo.output_scanline - top));
732 : }
733 0 : }
734 :
735 : // Override the standard error method in the IJG JPEG decoder code.
736 : METHODDEF(void)
737 0 : my_error_exit (j_common_ptr cinfo)
738 : {
739 0 : decoder_error_mgr* err = (decoder_error_mgr*) cinfo->err;
740 :
741 : // Convert error to a browser error code
742 0 : nsresult error_code = err->pub.msg_code == JERR_OUT_OF_MEMORY
743 0 : ? NS_ERROR_OUT_OF_MEMORY
744 0 : : NS_ERROR_FAILURE;
745 :
746 : #ifdef DEBUG
747 : char buffer[JMSG_LENGTH_MAX];
748 :
749 : // Create the message
750 0 : (*err->pub.format_message) (cinfo, buffer);
751 :
752 0 : fprintf(stderr, "JPEG decoding error:\n%s\n", buffer);
753 : #endif
754 :
755 : // Return control to the setjmp point. We pass an nsresult masquerading as
756 : // an int, which works because the setjmp() caller casts it back.
757 0 : longjmp(err->setjmp_buffer, static_cast<int>(error_code));
758 : }
759 :
760 : /*******************************************************************************
761 : * This is the callback routine from the IJG JPEG library used to supply new
762 : * data to the decompressor when its input buffer is exhausted. It juggles
763 : * multiple buffers in an attempt to avoid unnecessary copying of input data.
764 : *
765 : * (A simpler scheme is possible: It's much easier to use only a single
766 : * buffer; when fill_input_buffer() is called, move any unconsumed data
767 : * (beyond the current pointer/count) down to the beginning of this buffer and
768 : * then load new data into the remaining buffer space. This approach requires
769 : * a little more data copying but is far easier to get right.)
770 : *
771 : * At any one time, the JPEG decompressor is either reading from the necko
772 : * input buffer, which is volatile across top-level calls to the IJG library,
773 : * or the "backtrack" buffer. The backtrack buffer contains the remaining
774 : * unconsumed data from the necko buffer after parsing was suspended due
775 : * to insufficient data in some previous call to the IJG library.
776 : *
777 : * When suspending, the decompressor will back up to a convenient restart
778 : * point (typically the start of the current MCU). The variables
779 : * next_input_byte & bytes_in_buffer indicate where the restart point will be
780 : * if the current call returns FALSE. Data beyond this point must be
781 : * rescanned after resumption, so it must be preserved in case the decompressor
782 : * decides to backtrack.
783 : *
784 : * Returns:
785 : * TRUE if additional data is available, FALSE if no data present and
786 : * the JPEG library should therefore suspend processing of input stream
787 : ******************************************************************************/
788 :
789 : /******************************************************************************/
790 : /* data source manager method */
791 : /******************************************************************************/
792 :
793 : /******************************************************************************/
794 : /* data source manager method
795 : Initialize source. This is called by jpeg_read_header() before any
796 : data is actually read. May leave
797 : bytes_in_buffer set to 0 (in which case a fill_input_buffer() call
798 : will occur immediately).
799 : */
800 : METHODDEF(void)
801 0 : init_source (j_decompress_ptr jd)
802 : {
803 0 : }
804 :
805 : /******************************************************************************/
806 : /* data source manager method
807 : Skip num_bytes worth of data. The buffer pointer and count should
808 : be advanced over num_bytes input bytes, refilling the buffer as
809 : needed. This is used to skip over a potentially large amount of
810 : uninteresting data (such as an APPn marker). In some applications
811 : it may be possible to optimize away the reading of the skipped data,
812 : but it's not clear that being smart is worth much trouble; large
813 : skips are uncommon. bytes_in_buffer may be zero on return.
814 : A zero or negative skip count should be treated as a no-op.
815 : */
816 : METHODDEF(void)
817 0 : skip_input_data (j_decompress_ptr jd, long num_bytes)
818 : {
819 0 : struct jpeg_source_mgr* src = jd->src;
820 0 : nsJPEGDecoder* decoder = (nsJPEGDecoder*)(jd->client_data);
821 :
822 0 : if (num_bytes > (long)src->bytes_in_buffer) {
823 : // Can't skip it all right now until we get more data from
824 : // network stream. Set things up so that fill_input_buffer
825 : // will skip remaining amount.
826 0 : decoder->mBytesToSkip = (size_t)num_bytes - src->bytes_in_buffer;
827 0 : src->next_input_byte += src->bytes_in_buffer;
828 0 : src->bytes_in_buffer = 0;
829 :
830 : } else {
831 : // Simple case. Just advance buffer pointer
832 :
833 0 : src->bytes_in_buffer -= (size_t)num_bytes;
834 0 : src->next_input_byte += num_bytes;
835 : }
836 0 : }
837 :
838 : /******************************************************************************/
839 : /* data source manager method
840 : This is called whenever bytes_in_buffer has reached zero and more
841 : data is wanted. In typical applications, it should read fresh data
842 : into the buffer (ignoring the current state of next_input_byte and
843 : bytes_in_buffer), reset the pointer & count to the start of the
844 : buffer, and return TRUE indicating that the buffer has been reloaded.
845 : It is not necessary to fill the buffer entirely, only to obtain at
846 : least one more byte. bytes_in_buffer MUST be set to a positive value
847 : if TRUE is returned. A FALSE return should only be used when I/O
848 : suspension is desired.
849 : */
850 : METHODDEF(boolean)
851 0 : fill_input_buffer (j_decompress_ptr jd)
852 : {
853 0 : struct jpeg_source_mgr* src = jd->src;
854 0 : nsJPEGDecoder* decoder = (nsJPEGDecoder*)(jd->client_data);
855 :
856 0 : if (decoder->mReading) {
857 0 : const JOCTET* new_buffer = decoder->mSegment;
858 0 : uint32_t new_buflen = decoder->mSegmentLen;
859 :
860 0 : if (!new_buffer || new_buflen == 0) {
861 0 : return false; // suspend
862 : }
863 :
864 0 : decoder->mSegmentLen = 0;
865 :
866 0 : if (decoder->mBytesToSkip) {
867 0 : if (decoder->mBytesToSkip < new_buflen) {
868 : // All done skipping bytes; Return what's left.
869 0 : new_buffer += decoder->mBytesToSkip;
870 0 : new_buflen -= decoder->mBytesToSkip;
871 0 : decoder->mBytesToSkip = 0;
872 : } else {
873 : // Still need to skip some more data in the future
874 0 : decoder->mBytesToSkip -= (size_t)new_buflen;
875 0 : return false; // suspend
876 : }
877 : }
878 :
879 0 : decoder->mBackBufferUnreadLen = src->bytes_in_buffer;
880 :
881 0 : src->next_input_byte = new_buffer;
882 0 : src->bytes_in_buffer = (size_t)new_buflen;
883 0 : decoder->mReading = false;
884 :
885 0 : return true;
886 : }
887 :
888 0 : if (src->next_input_byte != decoder->mSegment) {
889 : // Backtrack data has been permanently consumed.
890 0 : decoder->mBackBufferUnreadLen = 0;
891 0 : decoder->mBackBufferLen = 0;
892 : }
893 :
894 : // Save remainder of netlib buffer in backtrack buffer
895 0 : const uint32_t new_backtrack_buflen = src->bytes_in_buffer +
896 0 : decoder->mBackBufferLen;
897 :
898 : // Make sure backtrack buffer is big enough to hold new data.
899 0 : if (decoder->mBackBufferSize < new_backtrack_buflen) {
900 : // Check for malformed MARKER segment lengths, before allocating space
901 : // for it
902 0 : if (new_backtrack_buflen > MAX_JPEG_MARKER_LENGTH) {
903 0 : my_error_exit((j_common_ptr)(&decoder->mInfo));
904 : }
905 :
906 : // Round up to multiple of 256 bytes.
907 0 : const size_t roundup_buflen = ((new_backtrack_buflen + 255) >> 8) << 8;
908 0 : JOCTET* buf = (JOCTET*) realloc(decoder->mBackBuffer, roundup_buflen);
909 : // Check for OOM
910 0 : if (!buf) {
911 0 : decoder->mInfo.err->msg_code = JERR_OUT_OF_MEMORY;
912 0 : my_error_exit((j_common_ptr)(&decoder->mInfo));
913 : }
914 0 : decoder->mBackBuffer = buf;
915 0 : decoder->mBackBufferSize = roundup_buflen;
916 : }
917 :
918 : // Copy remainder of netlib segment into backtrack buffer.
919 0 : memmove(decoder->mBackBuffer + decoder->mBackBufferLen,
920 0 : src->next_input_byte,
921 0 : src->bytes_in_buffer);
922 :
923 : // Point to start of data to be rescanned.
924 0 : src->next_input_byte = decoder->mBackBuffer + decoder->mBackBufferLen -
925 0 : decoder->mBackBufferUnreadLen;
926 0 : src->bytes_in_buffer += decoder->mBackBufferUnreadLen;
927 0 : decoder->mBackBufferLen = (size_t)new_backtrack_buflen;
928 0 : decoder->mReading = true;
929 :
930 0 : return false;
931 : }
932 :
933 : /******************************************************************************/
934 : /* data source manager method */
935 : /*
936 : * Terminate source --- called by jpeg_finish_decompress() after all
937 : * data has been read to clean up JPEG source manager. NOT called by
938 : * jpeg_abort() or jpeg_destroy().
939 : */
940 : METHODDEF(void)
941 0 : term_source (j_decompress_ptr jd)
942 : {
943 0 : nsJPEGDecoder* decoder = (nsJPEGDecoder*)(jd->client_data);
944 :
945 : // This function shouldn't be called if we ran into an error we didn't
946 : // recover from.
947 0 : MOZ_ASSERT(decoder->mState != JPEG_ERROR,
948 : "Calling term_source on a JPEG with mState == JPEG_ERROR!");
949 :
950 : // Notify using a helper method to get around protectedness issues.
951 0 : decoder->NotifyDone();
952 0 : }
953 :
954 : } // namespace image
955 : } // namespace mozilla
956 :
957 : ///*************** Inverted CMYK -> RGB conversion *************************
958 : /// Input is (Inverted) CMYK stored as 4 bytes per pixel.
959 : /// Output is RGB stored as 3 bytes per pixel.
960 : /// @param row Points to row buffer containing the CMYK bytes for each pixel
961 : /// in the row.
962 : /// @param width Number of pixels in the row.
963 0 : static void cmyk_convert_rgb(JSAMPROW row, JDIMENSION width)
964 : {
965 : // Work from end to front to shrink from 4 bytes per pixel to 3
966 0 : JSAMPROW in = row + width*4;
967 0 : JSAMPROW out = in;
968 :
969 0 : for (uint32_t i = width; i > 0; i--) {
970 0 : in -= 4;
971 0 : out -= 3;
972 :
973 : // Source is 'Inverted CMYK', output is RGB.
974 : // See: http://www.easyrgb.com/math.php?MATH=M12#text12
975 : // Or: http://www.ilkeratalay.com/colorspacesfaq.php#rgb
976 :
977 : // From CMYK to CMY
978 : // C = ( C * ( 1 - K ) + K )
979 : // M = ( M * ( 1 - K ) + K )
980 : // Y = ( Y * ( 1 - K ) + K )
981 :
982 : // From Inverted CMYK to CMY is thus:
983 : // C = ( (1-iC) * (1 - (1-iK)) + (1-iK) ) => 1 - iC*iK
984 : // Same for M and Y
985 :
986 : // Convert from CMY (0..1) to RGB (0..1)
987 : // R = 1 - C => 1 - (1 - iC*iK) => iC*iK
988 : // G = 1 - M => 1 - (1 - iM*iK) => iM*iK
989 : // B = 1 - Y => 1 - (1 - iY*iK) => iY*iK
990 :
991 : // Convert from Inverted CMYK (0..255) to RGB (0..255)
992 0 : const uint32_t iC = in[0];
993 0 : const uint32_t iM = in[1];
994 0 : const uint32_t iY = in[2];
995 0 : const uint32_t iK = in[3];
996 0 : out[0] = iC*iK/255; // Red
997 0 : out[1] = iM*iK/255; // Green
998 0 : out[2] = iY*iK/255; // Blue
999 : }
1000 0 : }
|