Backed out changeset 177eae915693 (bug 1206581) for bustage
[gecko.git] / image / decoders / nsJPEGDecoder.cpp
blobb9d8619a742f654a6b9318314daf7f64234485e2
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 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/. */
7 #include "ImageLogging.h"
8 #include "nsJPEGDecoder.h"
9 #include "Orientation.h"
10 #include "EXIF.h"
12 #include "nsIInputStream.h"
14 #include "nspr.h"
15 #include "nsCRT.h"
16 #include "gfxColor.h"
18 #include "jerror.h"
20 #include "gfxPlatform.h"
21 #include "mozilla/Endian.h"
22 #include "mozilla/Telemetry.h"
24 extern "C" {
25 #include "iccjpeg.h"
28 #if MOZ_BIG_ENDIAN
29 #define MOZ_JCS_EXT_NATIVE_ENDIAN_XRGB JCS_EXT_XRGB
30 #else
31 #define MOZ_JCS_EXT_NATIVE_ENDIAN_XRGB JCS_EXT_BGRX
32 #endif
34 static void cmyk_convert_rgb(JSAMPROW row, JDIMENSION width);
36 namespace mozilla {
37 namespace image {
39 static PRLogModuleInfo*
40 GetJPEGLog()
42 static PRLogModuleInfo* sJPEGLog;
43 if (!sJPEGLog) {
44 sJPEGLog = PR_NewLogModule("JPEGDecoder");
46 return sJPEGLog;
49 static PRLogModuleInfo*
50 GetJPEGDecoderAccountingLog()
52 static PRLogModuleInfo* sJPEGDecoderAccountingLog;
53 if (!sJPEGDecoderAccountingLog) {
54 sJPEGDecoderAccountingLog = PR_NewLogModule("JPEGDecoderAccounting");
56 return sJPEGDecoderAccountingLog;
59 static qcms_profile*
60 GetICCProfile(struct jpeg_decompress_struct& info)
62 JOCTET* profilebuf;
63 uint32_t profileLength;
64 qcms_profile* profile = nullptr;
66 if (read_icc_profile(&info, &profilebuf, &profileLength)) {
67 profile = qcms_profile_from_memory(profilebuf, profileLength);
68 free(profilebuf);
71 return profile;
74 METHODDEF(void) init_source (j_decompress_ptr jd);
75 METHODDEF(boolean) fill_input_buffer (j_decompress_ptr jd);
76 METHODDEF(void) skip_input_data (j_decompress_ptr jd, long num_bytes);
77 METHODDEF(void) term_source (j_decompress_ptr jd);
78 METHODDEF(void) my_error_exit (j_common_ptr cinfo);
80 // Normal JFIF markers can't have more bytes than this.
81 #define MAX_JPEG_MARKER_LENGTH (((uint32_t)1 << 16) - 1)
83 nsJPEGDecoder::nsJPEGDecoder(RasterImage* aImage,
84 Decoder::DecodeStyle aDecodeStyle)
85 : Decoder(aImage)
86 , mDecodeStyle(aDecodeStyle)
87 , mSampleSize(0)
89 mState = JPEG_HEADER;
90 mReading = true;
91 mImageData = nullptr;
93 mBytesToSkip = 0;
94 memset(&mInfo, 0, sizeof(jpeg_decompress_struct));
95 memset(&mSourceMgr, 0, sizeof(mSourceMgr));
96 mInfo.client_data = (void*)this;
98 mSegment = nullptr;
99 mSegmentLen = 0;
101 mBackBuffer = nullptr;
102 mBackBufferLen = mBackBufferSize = mBackBufferUnreadLen = 0;
104 mInProfile = nullptr;
105 mTransform = nullptr;
107 mCMSMode = 0;
109 MOZ_LOG(GetJPEGDecoderAccountingLog(), LogLevel::Debug,
110 ("nsJPEGDecoder::nsJPEGDecoder: Creating JPEG decoder %p",
111 this));
114 nsJPEGDecoder::~nsJPEGDecoder()
116 // Step 8: Release JPEG decompression object
117 mInfo.src = nullptr;
118 jpeg_destroy_decompress(&mInfo);
120 PR_FREEIF(mBackBuffer);
121 if (mTransform) {
122 qcms_transform_release(mTransform);
124 if (mInProfile) {
125 qcms_profile_release(mInProfile);
128 MOZ_LOG(GetJPEGDecoderAccountingLog(), LogLevel::Debug,
129 ("nsJPEGDecoder::~nsJPEGDecoder: Destroying JPEG decoder %p",
130 this));
133 Telemetry::ID
134 nsJPEGDecoder::SpeedHistogram()
136 return Telemetry::IMAGE_DECODE_SPEED_JPEG;
139 void
140 nsJPEGDecoder::InitInternal()
142 mCMSMode = gfxPlatform::GetCMSMode();
143 if (GetSurfaceFlags() & SurfaceFlags::NO_COLORSPACE_CONVERSION) {
144 mCMSMode = eCMSMode_Off;
147 // We set up the normal JPEG error routines, then override error_exit.
148 mInfo.err = jpeg_std_error(&mErr.pub);
149 // mInfo.err = jpeg_std_error(&mErr.pub);
150 mErr.pub.error_exit = my_error_exit;
151 // Establish the setjmp return context for my_error_exit to use.
152 if (setjmp(mErr.setjmp_buffer)) {
153 // If we get here, the JPEG code has signaled an error.
154 // We need to clean up the JPEG object, close the input file, and return.
155 PostDecoderError(NS_ERROR_FAILURE);
156 return;
159 // Step 1: allocate and initialize JPEG decompression object
160 jpeg_create_decompress(&mInfo);
161 // Set the source manager
162 mInfo.src = &mSourceMgr;
164 // Step 2: specify data source (eg, a file)
166 // Setup callback functions.
167 mSourceMgr.init_source = init_source;
168 mSourceMgr.fill_input_buffer = fill_input_buffer;
169 mSourceMgr.skip_input_data = skip_input_data;
170 mSourceMgr.resync_to_restart = jpeg_resync_to_restart;
171 mSourceMgr.term_source = term_source;
173 // Record app markers for ICC data
174 for (uint32_t m = 0; m < 16; m++) {
175 jpeg_save_markers(&mInfo, JPEG_APP0 + m, 0xFFFF);
179 void
180 nsJPEGDecoder::FinishInternal()
182 // If we're not in any sort of error case, force our state to JPEG_DONE.
183 if ((mState != JPEG_DONE && mState != JPEG_SINK_NON_JPEG_TRAILER) &&
184 (mState != JPEG_ERROR) &&
185 !IsMetadataDecode()) {
186 mState = JPEG_DONE;
190 void
191 nsJPEGDecoder::WriteInternal(const char* aBuffer, uint32_t aCount)
193 mSegment = (const JOCTET*)aBuffer;
194 mSegmentLen = aCount;
196 MOZ_ASSERT(!HasError(), "Shouldn't call WriteInternal after error!");
198 // Return here if there is a fatal error within libjpeg.
199 nsresult error_code;
200 // This cast to nsresult makes sense because setjmp() returns whatever we
201 // passed to longjmp(), which was actually an nsresult.
202 if ((error_code = (nsresult)setjmp(mErr.setjmp_buffer)) != NS_OK) {
203 if (error_code == NS_ERROR_FAILURE) {
204 PostDataError();
205 // Error due to corrupt stream - return NS_OK and consume silently
206 // so that ImageLib doesn't throw away a partial image load
207 mState = JPEG_SINK_NON_JPEG_TRAILER;
208 MOZ_LOG(GetJPEGDecoderAccountingLog(), LogLevel::Debug,
209 ("} (setjmp returned NS_ERROR_FAILURE)"));
210 return;
211 } else {
212 // Error due to reasons external to the stream (probably out of
213 // memory) - let ImageLib attempt to clean up, even though
214 // mozilla is seconds away from falling flat on its face.
215 PostDecoderError(error_code);
216 mState = JPEG_ERROR;
217 MOZ_LOG(GetJPEGDecoderAccountingLog(), LogLevel::Debug,
218 ("} (setjmp returned an error)"));
219 return;
223 MOZ_LOG(GetJPEGLog(), LogLevel::Debug,
224 ("[this=%p] nsJPEGDecoder::Write -- processing JPEG data\n", this));
226 switch (mState) {
227 case JPEG_HEADER: {
228 LOG_SCOPE(GetJPEGLog(), "nsJPEGDecoder::Write -- entering JPEG_HEADER"
229 " case");
231 // Step 3: read file parameters with jpeg_read_header()
232 if (jpeg_read_header(&mInfo, TRUE) == JPEG_SUSPENDED) {
233 MOZ_LOG(GetJPEGDecoderAccountingLog(), LogLevel::Debug,
234 ("} (JPEG_SUSPENDED)"));
235 return; // I/O suspension
238 // If we have a sample size specified for -moz-sample-size, use it.
239 if (mSampleSize > 0) {
240 mInfo.scale_num = 1;
241 mInfo.scale_denom = mSampleSize;
244 // Used to set up image size so arrays can be allocated
245 jpeg_calc_output_dimensions(&mInfo);
247 // Post our size to the superclass
248 PostSize(mInfo.output_width, mInfo.output_height,
249 ReadOrientationFromEXIF());
250 if (HasError()) {
251 // Setting the size led to an error.
252 mState = JPEG_ERROR;
253 return;
256 // If we're doing a metadata decode, we're done.
257 if (IsMetadataDecode()) {
258 return;
261 // We're doing a full decode.
262 if (mCMSMode != eCMSMode_Off &&
263 (mInProfile = GetICCProfile(mInfo)) != nullptr) {
264 uint32_t profileSpace = qcms_profile_get_color_space(mInProfile);
265 bool mismatch = false;
267 #ifdef DEBUG_tor
268 fprintf(stderr, "JPEG profileSpace: 0x%08X\n", profileSpace);
269 #endif
270 switch (mInfo.jpeg_color_space) {
271 case JCS_GRAYSCALE:
272 if (profileSpace == icSigRgbData) {
273 mInfo.out_color_space = JCS_RGB;
274 } else if (profileSpace != icSigGrayData) {
275 mismatch = true;
277 break;
278 case JCS_RGB:
279 if (profileSpace != icSigRgbData) {
280 mismatch = true;
282 break;
283 case JCS_YCbCr:
284 if (profileSpace == icSigRgbData) {
285 mInfo.out_color_space = JCS_RGB;
286 } else {
287 // qcms doesn't support ycbcr
288 mismatch = true;
290 break;
291 case JCS_CMYK:
292 case JCS_YCCK:
293 // qcms doesn't support cmyk
294 mismatch = true;
295 break;
296 default:
297 mState = JPEG_ERROR;
298 PostDataError();
299 MOZ_LOG(GetJPEGDecoderAccountingLog(), LogLevel::Debug,
300 ("} (unknown colorpsace (1))"));
301 return;
304 if (!mismatch) {
305 qcms_data_type type;
306 switch (mInfo.out_color_space) {
307 case JCS_GRAYSCALE:
308 type = QCMS_DATA_GRAY_8;
309 break;
310 case JCS_RGB:
311 type = QCMS_DATA_RGB_8;
312 break;
313 default:
314 mState = JPEG_ERROR;
315 PostDataError();
316 MOZ_LOG(GetJPEGDecoderAccountingLog(), LogLevel::Debug,
317 ("} (unknown colorpsace (2))"));
318 return;
320 #if 0
321 // We don't currently support CMYK profiles. The following
322 // code dealt with lcms types. Add something like this
323 // back when we gain support for CMYK.
325 // Adobe Photoshop writes YCCK/CMYK files with inverted data
326 if (mInfo.out_color_space == JCS_CMYK) {
327 type |= FLAVOR_SH(mInfo.saw_Adobe_marker ? 1 : 0);
329 #endif
331 if (gfxPlatform::GetCMSOutputProfile()) {
333 // Calculate rendering intent.
334 int intent = gfxPlatform::GetRenderingIntent();
335 if (intent == -1) {
336 intent = qcms_profile_get_rendering_intent(mInProfile);
339 // Create the color management transform.
340 mTransform = qcms_transform_create(mInProfile,
341 type,
342 gfxPlatform::GetCMSOutputProfile(),
343 QCMS_DATA_RGB_8,
344 (qcms_intent)intent);
346 } else {
347 #ifdef DEBUG_tor
348 fprintf(stderr, "ICM profile colorspace mismatch\n");
349 #endif
353 if (!mTransform) {
354 switch (mInfo.jpeg_color_space) {
355 case JCS_GRAYSCALE:
356 case JCS_RGB:
357 case JCS_YCbCr:
358 // if we're not color managing we can decode directly to
359 // MOZ_JCS_EXT_NATIVE_ENDIAN_XRGB
360 if (mCMSMode != eCMSMode_All) {
361 mInfo.out_color_space = MOZ_JCS_EXT_NATIVE_ENDIAN_XRGB;
362 mInfo.out_color_components = 4;
363 } else {
364 mInfo.out_color_space = JCS_RGB;
366 break;
367 case JCS_CMYK:
368 case JCS_YCCK:
369 // libjpeg can convert from YCCK to CMYK, but not to RGB
370 mInfo.out_color_space = JCS_CMYK;
371 break;
372 default:
373 mState = JPEG_ERROR;
374 PostDataError();
375 MOZ_LOG(GetJPEGDecoderAccountingLog(), LogLevel::Debug,
376 ("} (unknown colorpsace (3))"));
377 return;
381 // Don't allocate a giant and superfluous memory buffer
382 // when not doing a progressive decode.
383 mInfo.buffered_image = mDecodeStyle == PROGRESSIVE &&
384 jpeg_has_multiple_scans(&mInfo);
386 MOZ_ASSERT(!mImageData, "Already have a buffer allocated?");
387 nsIntSize targetSize = mDownscaler ? mDownscaler->TargetSize() : GetSize();
388 nsresult rv = AllocateFrame(0, targetSize,
389 nsIntRect(nsIntPoint(), targetSize),
390 gfx::SurfaceFormat::B8G8R8A8);
391 if (NS_FAILED(rv)) {
392 mState = JPEG_ERROR;
393 MOZ_LOG(GetJPEGDecoderAccountingLog(), LogLevel::Debug,
394 ("} (could not initialize image frame)"));
395 return;
398 MOZ_ASSERT(mImageData, "Should have a buffer now");
400 if (mDownscaler) {
401 nsresult rv = mDownscaler->BeginFrame(GetSize(), Nothing(),
402 mImageData,
403 /* aHasAlpha = */ false);
404 if (NS_FAILED(rv)) {
405 mState = JPEG_ERROR;
406 return;
410 MOZ_LOG(GetJPEGDecoderAccountingLog(), LogLevel::Debug,
411 (" JPEGDecoderAccounting: nsJPEGDecoder::"
412 "Write -- created image frame with %ux%u pixels",
413 mInfo.output_width, mInfo.output_height));
415 mState = JPEG_START_DECOMPRESS;
418 case JPEG_START_DECOMPRESS: {
419 LOG_SCOPE(GetJPEGLog(), "nsJPEGDecoder::Write -- entering"
420 " JPEG_START_DECOMPRESS case");
421 // Step 4: set parameters for decompression
423 // FIXME -- Should reset dct_method and dither mode
424 // for final pass of progressive JPEG
426 mInfo.dct_method = JDCT_ISLOW;
427 mInfo.dither_mode = JDITHER_FS;
428 mInfo.do_fancy_upsampling = TRUE;
429 mInfo.enable_2pass_quant = FALSE;
430 mInfo.do_block_smoothing = TRUE;
432 // Step 5: Start decompressor
433 if (jpeg_start_decompress(&mInfo) == FALSE) {
434 MOZ_LOG(GetJPEGDecoderAccountingLog(), LogLevel::Debug,
435 ("} (I/O suspension after jpeg_start_decompress())"));
436 return; // I/O suspension
439 // If this is a progressive JPEG ...
440 mState = mInfo.buffered_image ?
441 JPEG_DECOMPRESS_PROGRESSIVE : JPEG_DECOMPRESS_SEQUENTIAL;
444 case JPEG_DECOMPRESS_SEQUENTIAL: {
445 if (mState == JPEG_DECOMPRESS_SEQUENTIAL) {
446 LOG_SCOPE(GetJPEGLog(), "nsJPEGDecoder::Write -- "
447 "JPEG_DECOMPRESS_SEQUENTIAL case");
449 bool suspend;
450 OutputScanlines(&suspend);
452 if (suspend) {
453 MOZ_LOG(GetJPEGDecoderAccountingLog(), LogLevel::Debug,
454 ("} (I/O suspension after OutputScanlines() - SEQUENTIAL)"));
455 return; // I/O suspension
458 // If we've completed image output ...
459 NS_ASSERTION(mInfo.output_scanline == mInfo.output_height,
460 "We didn't process all of the data!");
461 mState = JPEG_DONE;
465 case JPEG_DECOMPRESS_PROGRESSIVE: {
466 if (mState == JPEG_DECOMPRESS_PROGRESSIVE) {
467 LOG_SCOPE(GetJPEGLog(),
468 "nsJPEGDecoder::Write -- JPEG_DECOMPRESS_PROGRESSIVE case");
470 int status;
471 do {
472 status = jpeg_consume_input(&mInfo);
473 } while ((status != JPEG_SUSPENDED) &&
474 (status != JPEG_REACHED_EOI));
476 for (;;) {
477 if (mInfo.output_scanline == 0) {
478 int scan = mInfo.input_scan_number;
480 // if we haven't displayed anything yet (output_scan_number==0)
481 // and we have enough data for a complete scan, force output
482 // of the last full scan
483 if ((mInfo.output_scan_number == 0) &&
484 (scan > 1) &&
485 (status != JPEG_REACHED_EOI))
486 scan--;
488 if (!jpeg_start_output(&mInfo, scan)) {
489 MOZ_LOG(GetJPEGDecoderAccountingLog(), LogLevel::Debug,
490 ("} (I/O suspension after jpeg_start_output() -"
491 " PROGRESSIVE)"));
492 return; // I/O suspension
496 if (mInfo.output_scanline == 0xffffff) {
497 mInfo.output_scanline = 0;
500 bool suspend;
501 OutputScanlines(&suspend);
503 if (suspend) {
504 if (mInfo.output_scanline == 0) {
505 // didn't manage to read any lines - flag so we don't call
506 // jpeg_start_output() multiple times for the same scan
507 mInfo.output_scanline = 0xffffff;
509 MOZ_LOG(GetJPEGDecoderAccountingLog(), LogLevel::Debug,
510 ("} (I/O suspension after OutputScanlines() - PROGRESSIVE)"));
511 return; // I/O suspension
514 if (mInfo.output_scanline == mInfo.output_height) {
515 if (!jpeg_finish_output(&mInfo)) {
516 MOZ_LOG(GetJPEGDecoderAccountingLog(), LogLevel::Debug,
517 ("} (I/O suspension after jpeg_finish_output() -"
518 " PROGRESSIVE)"));
519 return; // I/O suspension
522 if (jpeg_input_complete(&mInfo) &&
523 (mInfo.input_scan_number == mInfo.output_scan_number))
524 break;
526 mInfo.output_scanline = 0;
527 if (mDownscaler) {
528 mDownscaler->ResetForNextProgressivePass();
533 mState = JPEG_DONE;
537 case JPEG_DONE: {
538 LOG_SCOPE(GetJPEGLog(), "nsJPEGDecoder::ProcessData -- entering"
539 " JPEG_DONE case");
541 // Step 7: Finish decompression
543 if (jpeg_finish_decompress(&mInfo) == FALSE) {
544 MOZ_LOG(GetJPEGDecoderAccountingLog(), LogLevel::Debug,
545 ("} (I/O suspension after jpeg_finish_decompress() - DONE)"));
546 return; // I/O suspension
549 mState = JPEG_SINK_NON_JPEG_TRAILER;
551 // we're done dude
552 break;
554 case JPEG_SINK_NON_JPEG_TRAILER:
555 MOZ_LOG(GetJPEGLog(), LogLevel::Debug,
556 ("[this=%p] nsJPEGDecoder::ProcessData -- entering"
557 " JPEG_SINK_NON_JPEG_TRAILER case\n", this));
559 break;
561 case JPEG_ERROR:
562 MOZ_ASSERT(false,
563 "Should always return immediately after error and not re-enter "
564 "decoder");
567 MOZ_LOG(GetJPEGDecoderAccountingLog(), LogLevel::Debug,
568 ("} (end of function)"));
569 return;
572 Orientation
573 nsJPEGDecoder::ReadOrientationFromEXIF()
575 jpeg_saved_marker_ptr marker;
577 // Locate the APP1 marker, where EXIF data is stored, in the marker list.
578 for (marker = mInfo.marker_list ; marker != nullptr ; marker = marker->next) {
579 if (marker->marker == JPEG_APP0 + 1) {
580 break;
584 // If we're at the end of the list, there's no EXIF data.
585 if (!marker) {
586 return Orientation();
589 // Extract the orientation information.
590 EXIFData exif = EXIFParser::Parse(marker->data,
591 static_cast<uint32_t>(marker->data_length));
592 return exif.orientation;
595 void
596 nsJPEGDecoder::NotifyDone()
598 PostFrameStop(Opacity::OPAQUE);
599 PostDecodeDone();
602 void
603 nsJPEGDecoder::OutputScanlines(bool* suspend)
605 *suspend = false;
607 const uint32_t top = mInfo.output_scanline;
609 while ((mInfo.output_scanline < mInfo.output_height)) {
610 uint32_t* imageRow = nullptr;
611 if (mDownscaler) {
612 imageRow = reinterpret_cast<uint32_t*>(mDownscaler->RowBuffer());
613 } else {
614 imageRow = reinterpret_cast<uint32_t*>(mImageData) +
615 (mInfo.output_scanline * mInfo.output_width);
618 MOZ_ASSERT(imageRow, "Should have a row buffer here");
620 if (mInfo.out_color_space == MOZ_JCS_EXT_NATIVE_ENDIAN_XRGB) {
621 // Special case: scanline will be directly converted into packed ARGB
622 if (jpeg_read_scanlines(&mInfo, (JSAMPARRAY)&imageRow, 1) != 1) {
623 *suspend = true; // suspend
624 break;
626 if (mDownscaler) {
627 mDownscaler->CommitRow();
629 continue; // all done for this row!
632 JSAMPROW sampleRow = (JSAMPROW)imageRow;
633 if (mInfo.output_components == 3) {
634 // Put the pixels at end of row to enable in-place expansion
635 sampleRow += mInfo.output_width;
638 // Request one scanline. Returns 0 or 1 scanlines.
639 if (jpeg_read_scanlines(&mInfo, &sampleRow, 1) != 1) {
640 *suspend = true; // suspend
641 break;
644 if (mTransform) {
645 JSAMPROW source = sampleRow;
646 if (mInfo.out_color_space == JCS_GRAYSCALE) {
647 // Convert from the 1byte grey pixels at begin of row
648 // to the 3byte RGB byte pixels at 'end' of row
649 sampleRow += mInfo.output_width;
651 qcms_transform_data(mTransform, source, sampleRow, mInfo.output_width);
652 // Move 3byte RGB data to end of row
653 if (mInfo.out_color_space == JCS_CMYK) {
654 memmove(sampleRow + mInfo.output_width,
655 sampleRow,
656 3 * mInfo.output_width);
657 sampleRow += mInfo.output_width;
659 } else {
660 if (mInfo.out_color_space == JCS_CMYK) {
661 // Convert from CMYK to RGB
662 // We cannot convert directly to Cairo, as the CMSRGBTransform
663 // may wants to do a RGB transform...
664 // Would be better to have platform CMSenabled transformation
665 // from CMYK to (A)RGB...
666 cmyk_convert_rgb((JSAMPROW)imageRow, mInfo.output_width);
667 sampleRow += mInfo.output_width;
669 if (mCMSMode == eCMSMode_All) {
670 // No embedded ICC profile - treat as sRGB
671 qcms_transform* transform = gfxPlatform::GetCMSRGBTransform();
672 if (transform) {
673 qcms_transform_data(transform, sampleRow, sampleRow,
674 mInfo.output_width);
679 // counter for while() loops below
680 uint32_t idx = mInfo.output_width;
682 // copy as bytes until source pointer is 32-bit-aligned
683 for (; (NS_PTR_TO_UINT32(sampleRow) & 0x3) && idx; --idx) {
684 *imageRow++ = gfxPackedPixel(0xFF, sampleRow[0], sampleRow[1],
685 sampleRow[2]);
686 sampleRow += 3;
689 // copy pixels in blocks of 4
690 while (idx >= 4) {
691 GFX_BLOCK_RGB_TO_FRGB(sampleRow, imageRow);
692 idx -= 4;
693 sampleRow += 12;
694 imageRow += 4;
697 // copy remaining pixel(s)
698 while (idx--) {
699 // 32-bit read of final pixel will exceed buffer, so read bytes
700 *imageRow++ = gfxPackedPixel(0xFF, sampleRow[0], sampleRow[1],
701 sampleRow[2]);
702 sampleRow += 3;
705 if (mDownscaler) {
706 mDownscaler->CommitRow();
710 if (mDownscaler && mDownscaler->HasInvalidation()) {
711 DownscalerInvalidRect invalidRect = mDownscaler->TakeInvalidRect();
712 PostInvalidation(invalidRect.mOriginalSizeRect,
713 Some(invalidRect.mTargetSizeRect));
714 MOZ_ASSERT(!mDownscaler->HasInvalidation());
715 } else if (!mDownscaler && top != mInfo.output_scanline) {
716 PostInvalidation(nsIntRect(0, top,
717 mInfo.output_width,
718 mInfo.output_scanline - top));
722 // Override the standard error method in the IJG JPEG decoder code.
723 METHODDEF(void)
724 my_error_exit (j_common_ptr cinfo)
726 decoder_error_mgr* err = (decoder_error_mgr*) cinfo->err;
728 // Convert error to a browser error code
729 nsresult error_code = err->pub.msg_code == JERR_OUT_OF_MEMORY
730 ? NS_ERROR_OUT_OF_MEMORY
731 : NS_ERROR_FAILURE;
733 #ifdef DEBUG
734 char buffer[JMSG_LENGTH_MAX];
736 // Create the message
737 (*err->pub.format_message) (cinfo, buffer);
739 fprintf(stderr, "JPEG decoding error:\n%s\n", buffer);
740 #endif
742 // Return control to the setjmp point. We pass an nsresult masquerading as
743 // an int, which works because the setjmp() caller casts it back.
744 longjmp(err->setjmp_buffer, static_cast<int>(error_code));
747 /*******************************************************************************
748 * This is the callback routine from the IJG JPEG library used to supply new
749 * data to the decompressor when its input buffer is exhausted. It juggles
750 * multiple buffers in an attempt to avoid unnecessary copying of input data.
752 * (A simpler scheme is possible: It's much easier to use only a single
753 * buffer; when fill_input_buffer() is called, move any unconsumed data
754 * (beyond the current pointer/count) down to the beginning of this buffer and
755 * then load new data into the remaining buffer space. This approach requires
756 * a little more data copying but is far easier to get right.)
758 * At any one time, the JPEG decompressor is either reading from the necko
759 * input buffer, which is volatile across top-level calls to the IJG library,
760 * or the "backtrack" buffer. The backtrack buffer contains the remaining
761 * unconsumed data from the necko buffer after parsing was suspended due
762 * to insufficient data in some previous call to the IJG library.
764 * When suspending, the decompressor will back up to a convenient restart
765 * point (typically the start of the current MCU). The variables
766 * next_input_byte & bytes_in_buffer indicate where the restart point will be
767 * if the current call returns FALSE. Data beyond this point must be
768 * rescanned after resumption, so it must be preserved in case the decompressor
769 * decides to backtrack.
771 * Returns:
772 * TRUE if additional data is available, FALSE if no data present and
773 * the JPEG library should therefore suspend processing of input stream
774 ******************************************************************************/
776 /******************************************************************************/
777 /* data source manager method */
778 /******************************************************************************/
780 /******************************************************************************/
781 /* data source manager method
782 Initialize source. This is called by jpeg_read_header() before any
783 data is actually read. May leave
784 bytes_in_buffer set to 0 (in which case a fill_input_buffer() call
785 will occur immediately).
787 METHODDEF(void)
788 init_source (j_decompress_ptr jd)
792 /******************************************************************************/
793 /* data source manager method
794 Skip num_bytes worth of data. The buffer pointer and count should
795 be advanced over num_bytes input bytes, refilling the buffer as
796 needed. This is used to skip over a potentially large amount of
797 uninteresting data (such as an APPn marker). In some applications
798 it may be possible to optimize away the reading of the skipped data,
799 but it's not clear that being smart is worth much trouble; large
800 skips are uncommon. bytes_in_buffer may be zero on return.
801 A zero or negative skip count should be treated as a no-op.
803 METHODDEF(void)
804 skip_input_data (j_decompress_ptr jd, long num_bytes)
806 struct jpeg_source_mgr* src = jd->src;
807 nsJPEGDecoder* decoder = (nsJPEGDecoder*)(jd->client_data);
809 if (num_bytes > (long)src->bytes_in_buffer) {
810 // Can't skip it all right now until we get more data from
811 // network stream. Set things up so that fill_input_buffer
812 // will skip remaining amount.
813 decoder->mBytesToSkip = (size_t)num_bytes - src->bytes_in_buffer;
814 src->next_input_byte += src->bytes_in_buffer;
815 src->bytes_in_buffer = 0;
817 } else {
818 // Simple case. Just advance buffer pointer
820 src->bytes_in_buffer -= (size_t)num_bytes;
821 src->next_input_byte += num_bytes;
825 /******************************************************************************/
826 /* data source manager method
827 This is called whenever bytes_in_buffer has reached zero and more
828 data is wanted. In typical applications, it should read fresh data
829 into the buffer (ignoring the current state of next_input_byte and
830 bytes_in_buffer), reset the pointer & count to the start of the
831 buffer, and return TRUE indicating that the buffer has been reloaded.
832 It is not necessary to fill the buffer entirely, only to obtain at
833 least one more byte. bytes_in_buffer MUST be set to a positive value
834 if TRUE is returned. A FALSE return should only be used when I/O
835 suspension is desired.
837 METHODDEF(boolean)
838 fill_input_buffer (j_decompress_ptr jd)
840 struct jpeg_source_mgr* src = jd->src;
841 nsJPEGDecoder* decoder = (nsJPEGDecoder*)(jd->client_data);
843 if (decoder->mReading) {
844 const JOCTET* new_buffer = decoder->mSegment;
845 uint32_t new_buflen = decoder->mSegmentLen;
847 if (!new_buffer || new_buflen == 0) {
848 return false; // suspend
851 decoder->mSegmentLen = 0;
853 if (decoder->mBytesToSkip) {
854 if (decoder->mBytesToSkip < new_buflen) {
855 // All done skipping bytes; Return what's left.
856 new_buffer += decoder->mBytesToSkip;
857 new_buflen -= decoder->mBytesToSkip;
858 decoder->mBytesToSkip = 0;
859 } else {
860 // Still need to skip some more data in the future
861 decoder->mBytesToSkip -= (size_t)new_buflen;
862 return false; // suspend
866 decoder->mBackBufferUnreadLen = src->bytes_in_buffer;
868 src->next_input_byte = new_buffer;
869 src->bytes_in_buffer = (size_t)new_buflen;
870 decoder->mReading = false;
872 return true;
875 if (src->next_input_byte != decoder->mSegment) {
876 // Backtrack data has been permanently consumed.
877 decoder->mBackBufferUnreadLen = 0;
878 decoder->mBackBufferLen = 0;
881 // Save remainder of netlib buffer in backtrack buffer
882 const uint32_t new_backtrack_buflen = src->bytes_in_buffer +
883 decoder->mBackBufferLen;
885 // Make sure backtrack buffer is big enough to hold new data.
886 if (decoder->mBackBufferSize < new_backtrack_buflen) {
887 // Check for malformed MARKER segment lengths, before allocating space
888 // for it
889 if (new_backtrack_buflen > MAX_JPEG_MARKER_LENGTH) {
890 my_error_exit((j_common_ptr)(&decoder->mInfo));
893 // Round up to multiple of 256 bytes.
894 const size_t roundup_buflen = ((new_backtrack_buflen + 255) >> 8) << 8;
895 JOCTET* buf = (JOCTET*)PR_REALLOC(decoder->mBackBuffer, roundup_buflen);
896 // Check for OOM
897 if (!buf) {
898 decoder->mInfo.err->msg_code = JERR_OUT_OF_MEMORY;
899 my_error_exit((j_common_ptr)(&decoder->mInfo));
901 decoder->mBackBuffer = buf;
902 decoder->mBackBufferSize = roundup_buflen;
905 // Copy remainder of netlib segment into backtrack buffer.
906 memmove(decoder->mBackBuffer + decoder->mBackBufferLen,
907 src->next_input_byte,
908 src->bytes_in_buffer);
910 // Point to start of data to be rescanned.
911 src->next_input_byte = decoder->mBackBuffer + decoder->mBackBufferLen -
912 decoder->mBackBufferUnreadLen;
913 src->bytes_in_buffer += decoder->mBackBufferUnreadLen;
914 decoder->mBackBufferLen = (size_t)new_backtrack_buflen;
915 decoder->mReading = true;
917 return false;
920 /******************************************************************************/
921 /* data source manager method */
923 * Terminate source --- called by jpeg_finish_decompress() after all
924 * data has been read to clean up JPEG source manager. NOT called by
925 * jpeg_abort() or jpeg_destroy().
927 METHODDEF(void)
928 term_source (j_decompress_ptr jd)
930 nsJPEGDecoder* decoder = (nsJPEGDecoder*)(jd->client_data);
932 // This function shouldn't be called if we ran into an error we didn't
933 // recover from.
934 MOZ_ASSERT(decoder->mState != JPEG_ERROR,
935 "Calling term_source on a JPEG with mState == JPEG_ERROR!");
937 // Notify using a helper method to get around protectedness issues.
938 decoder->NotifyDone();
941 } // namespace image
942 } // namespace mozilla
944 ///*************** Inverted CMYK -> RGB conversion *************************
945 /// Input is (Inverted) CMYK stored as 4 bytes per pixel.
946 /// Output is RGB stored as 3 bytes per pixel.
947 /// @param row Points to row buffer containing the CMYK bytes for each pixel
948 /// in the row.
949 /// @param width Number of pixels in the row.
950 static void cmyk_convert_rgb(JSAMPROW row, JDIMENSION width)
952 // Work from end to front to shrink from 4 bytes per pixel to 3
953 JSAMPROW in = row + width*4;
954 JSAMPROW out = in;
956 for (uint32_t i = width; i > 0; i--) {
957 in -= 4;
958 out -= 3;
960 // Source is 'Inverted CMYK', output is RGB.
961 // See: http://www.easyrgb.com/math.php?MATH=M12#text12
962 // Or: http://www.ilkeratalay.com/colorspacesfaq.php#rgb
964 // From CMYK to CMY
965 // C = ( C * ( 1 - K ) + K )
966 // M = ( M * ( 1 - K ) + K )
967 // Y = ( Y * ( 1 - K ) + K )
969 // From Inverted CMYK to CMY is thus:
970 // C = ( (1-iC) * (1 - (1-iK)) + (1-iK) ) => 1 - iC*iK
971 // Same for M and Y
973 // Convert from CMY (0..1) to RGB (0..1)
974 // R = 1 - C => 1 - (1 - iC*iK) => iC*iK
975 // G = 1 - M => 1 - (1 - iM*iK) => iM*iK
976 // B = 1 - Y => 1 - (1 - iY*iK) => iY*iK
978 // Convert from Inverted CMYK (0..255) to RGB (0..255)
979 const uint32_t iC = in[0];
980 const uint32_t iM = in[1];
981 const uint32_t iY = in[2];
982 const uint32_t iK = in[3];
983 out[0] = iC*iK/255; // Red
984 out[1] = iM*iK/255; // Green
985 out[2] = iY*iK/255; // Blue