Bumping manifests a=b2g-bump
[gecko.git] / image / decoders / nsJPEGDecoder.cpp
blob77b517b66731e4089f05584f18619366ed1e534d
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"
22 extern "C" {
23 #include "iccjpeg.h"
26 #if defined(IS_BIG_ENDIAN)
27 #define MOZ_JCS_EXT_NATIVE_ENDIAN_XRGB JCS_EXT_XRGB
28 #else
29 #define MOZ_JCS_EXT_NATIVE_ENDIAN_XRGB JCS_EXT_BGRX
30 #endif
32 static void cmyk_convert_rgb(JSAMPROW row, JDIMENSION width);
34 namespace mozilla {
35 namespace image {
37 #if defined(PR_LOGGING)
38 static PRLogModuleInfo *
39 GetJPEGLog()
41 static PRLogModuleInfo *sJPEGLog;
42 if (!sJPEGLog)
43 sJPEGLog = PR_NewLogModule("JPEGDecoder");
44 return sJPEGLog;
47 static PRLogModuleInfo *
48 GetJPEGDecoderAccountingLog()
50 static PRLogModuleInfo *sJPEGDecoderAccountingLog;
51 if (!sJPEGDecoderAccountingLog)
52 sJPEGDecoderAccountingLog = PR_NewLogModule("JPEGDecoderAccounting");
53 return sJPEGDecoderAccountingLog;
55 #else
56 #define GetJPEGLog()
57 #define GetJPEGDecoderAccountingLog()
58 #endif
60 static qcms_profile*
61 GetICCProfile(struct jpeg_decompress_struct &info)
63 JOCTET* profilebuf;
64 uint32_t profileLength;
65 qcms_profile* profile = nullptr;
67 if (read_icc_profile(&info, &profilebuf, &profileLength)) {
68 profile = qcms_profile_from_memory(profilebuf, profileLength);
69 free(profilebuf);
72 return profile;
75 METHODDEF(void) init_source (j_decompress_ptr jd);
76 METHODDEF(boolean) fill_input_buffer (j_decompress_ptr jd);
77 METHODDEF(void) skip_input_data (j_decompress_ptr jd, long num_bytes);
78 METHODDEF(void) term_source (j_decompress_ptr jd);
79 METHODDEF(void) my_error_exit (j_common_ptr cinfo);
81 /* Normal JFIF markers can't have more bytes than this. */
82 #define MAX_JPEG_MARKER_LENGTH (((uint32_t)1 << 16) - 1)
85 nsJPEGDecoder::nsJPEGDecoder(RasterImage& aImage, Decoder::DecodeStyle aDecodeStyle)
86 : Decoder(aImage)
87 , mDecodeStyle(aDecodeStyle)
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 PR_LOG(GetJPEGDecoderAccountingLog(), PR_LOG_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);
123 if (mInProfile)
124 qcms_profile_release(mInProfile);
126 PR_LOG(GetJPEGDecoderAccountingLog(), PR_LOG_DEBUG,
127 ("nsJPEGDecoder::~nsJPEGDecoder: Destroying JPEG decoder %p",
128 this));
131 Telemetry::ID
132 nsJPEGDecoder::SpeedHistogram()
134 return Telemetry::IMAGE_DECODE_SPEED_JPEG;
137 void
138 nsJPEGDecoder::InitInternal()
140 mCMSMode = gfxPlatform::GetCMSMode();
141 if ((mDecodeFlags & DECODER_NO_COLORSPACE_CONVERSION) != 0)
142 mCMSMode = eCMSMode_Off;
144 /* We set up the normal JPEG error routines, then override error_exit. */
145 mInfo.err = jpeg_std_error(&mErr.pub);
146 /* mInfo.err = jpeg_std_error(&mErr.pub); */
147 mErr.pub.error_exit = my_error_exit;
148 /* Establish the setjmp return context for my_error_exit to use. */
149 if (setjmp(mErr.setjmp_buffer)) {
150 /* If we get here, the JPEG code has signaled an error.
151 * We need to clean up the JPEG object, close the input file, and return.
153 PostDecoderError(NS_ERROR_FAILURE);
154 return;
157 /* Step 1: allocate and initialize JPEG decompression object */
158 jpeg_create_decompress(&mInfo);
159 /* Set the source manager */
160 mInfo.src = &mSourceMgr;
162 /* Step 2: specify data source (eg, a file) */
164 /* Setup callback functions. */
165 mSourceMgr.init_source = init_source;
166 mSourceMgr.fill_input_buffer = fill_input_buffer;
167 mSourceMgr.skip_input_data = skip_input_data;
168 mSourceMgr.resync_to_restart = jpeg_resync_to_restart;
169 mSourceMgr.term_source = term_source;
171 /* Record app markers for ICC data */
172 for (uint32_t m = 0; m < 16; m++)
173 jpeg_save_markers(&mInfo, JPEG_APP0 + m, 0xFFFF);
176 void
177 nsJPEGDecoder::FinishInternal()
179 /* If we're not in any sort of error case, flush the decoder.
181 * XXXbholley - It seems wrong that this should be necessary, but at the
182 * moment I'm just folding the contents of Flush() into Close() so that
183 * we can get rid of it.
185 * XXX(seth): It'd be great to get rid of this. For now, we treat this as a
186 * write to a synchronous decoder, which means that this must be called only
187 * on the main thread. (That's asserted in Decoder::Finish and
188 * Decoder::FinishSharedDecoder.)
190 if ((mState != JPEG_DONE && mState != JPEG_SINK_NON_JPEG_TRAILER) &&
191 (mState != JPEG_ERROR) &&
192 !IsSizeDecode())
193 this->Write(nullptr, 0, DECODE_SYNC);
196 void
197 nsJPEGDecoder::WriteInternal(const char *aBuffer, uint32_t aCount, DecodeStrategy)
199 mSegment = (const JOCTET *)aBuffer;
200 mSegmentLen = aCount;
202 NS_ABORT_IF_FALSE(!HasError(), "Shouldn't call WriteInternal after error!");
204 /* Return here if there is a fatal error within libjpeg. */
205 nsresult error_code;
206 // This cast to nsresult makes sense because setjmp() returns whatever we
207 // passed to longjmp(), which was actually an nsresult.
208 if ((error_code = (nsresult)setjmp(mErr.setjmp_buffer)) != NS_OK) {
209 if (error_code == NS_ERROR_FAILURE) {
210 PostDataError();
211 /* Error due to corrupt stream - return NS_OK and consume silently
212 so that libpr0n doesn't throw away a partial image load */
213 mState = JPEG_SINK_NON_JPEG_TRAILER;
214 PR_LOG(GetJPEGDecoderAccountingLog(), PR_LOG_DEBUG,
215 ("} (setjmp returned NS_ERROR_FAILURE)"));
216 return;
217 } else {
218 /* Error due to reasons external to the stream (probably out of
219 memory) - let libpr0n attempt to clean up, even though
220 mozilla is seconds away from falling flat on its face. */
221 PostDecoderError(error_code);
222 mState = JPEG_ERROR;
223 PR_LOG(GetJPEGDecoderAccountingLog(), PR_LOG_DEBUG,
224 ("} (setjmp returned an error)"));
225 return;
229 PR_LOG(GetJPEGLog(), PR_LOG_DEBUG,
230 ("[this=%p] nsJPEGDecoder::Write -- processing JPEG data\n", this));
232 switch (mState) {
233 case JPEG_HEADER:
235 LOG_SCOPE(GetJPEGLog(), "nsJPEGDecoder::Write -- entering JPEG_HEADER case");
237 /* Step 3: read file parameters with jpeg_read_header() */
238 if (jpeg_read_header(&mInfo, TRUE) == JPEG_SUSPENDED) {
239 PR_LOG(GetJPEGDecoderAccountingLog(), PR_LOG_DEBUG,
240 ("} (JPEG_SUSPENDED)"));
241 return; /* I/O suspension */
244 int sampleSize = mImage.GetRequestedSampleSize();
245 if (sampleSize > 0) {
246 mInfo.scale_num = 1;
247 mInfo.scale_denom = sampleSize;
250 /* Used to set up image size so arrays can be allocated */
251 jpeg_calc_output_dimensions(&mInfo);
253 // Post our size to the superclass
254 PostSize(mInfo.output_width, mInfo.output_height, ReadOrientationFromEXIF());
255 if (HasError()) {
256 // Setting the size led to an error.
257 mState = JPEG_ERROR;
258 return;
261 /* If we're doing a size decode, we're done. */
262 if (IsSizeDecode())
263 return;
265 /* We're doing a full decode. */
266 if (mCMSMode != eCMSMode_Off &&
267 (mInProfile = GetICCProfile(mInfo)) != nullptr) {
268 uint32_t profileSpace = qcms_profile_get_color_space(mInProfile);
269 bool mismatch = false;
271 #ifdef DEBUG_tor
272 fprintf(stderr, "JPEG profileSpace: 0x%08X\n", profileSpace);
273 #endif
274 switch (mInfo.jpeg_color_space) {
275 case JCS_GRAYSCALE:
276 if (profileSpace == icSigRgbData)
277 mInfo.out_color_space = JCS_RGB;
278 else if (profileSpace != icSigGrayData)
279 mismatch = true;
280 break;
281 case JCS_RGB:
282 if (profileSpace != icSigRgbData)
283 mismatch = true;
284 break;
285 case JCS_YCbCr:
286 if (profileSpace == icSigRgbData)
287 mInfo.out_color_space = JCS_RGB;
288 else
289 // qcms doesn't support ycbcr
290 mismatch = true;
291 break;
292 case JCS_CMYK:
293 case JCS_YCCK:
294 // qcms doesn't support cmyk
295 mismatch = true;
296 break;
297 default:
298 mState = JPEG_ERROR;
299 PostDataError();
300 PR_LOG(GetJPEGDecoderAccountingLog(), PR_LOG_DEBUG,
301 ("} (unknown colorpsace (1))"));
302 return;
305 if (!mismatch) {
306 qcms_data_type type;
307 switch (mInfo.out_color_space) {
308 case JCS_GRAYSCALE:
309 type = QCMS_DATA_GRAY_8;
310 break;
311 case JCS_RGB:
312 type = QCMS_DATA_RGB_8;
313 break;
314 default:
315 mState = JPEG_ERROR;
316 PostDataError();
317 PR_LOG(GetJPEGDecoderAccountingLog(), PR_LOG_DEBUG,
318 ("} (unknown colorpsace (2))"));
319 return;
321 #if 0
322 /* We don't currently support CMYK profiles. The following
323 * code dealt with lcms types. Add something like this
324 * back when we gain support for CMYK.
326 /* Adobe Photoshop writes YCCK/CMYK files with inverted data */
327 if (mInfo.out_color_space == JCS_CMYK)
328 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);
338 /* Create the color management transform. */
339 mTransform = qcms_transform_create(mInProfile,
340 type,
341 gfxPlatform::GetCMSOutputProfile(),
342 QCMS_DATA_RGB_8,
343 (qcms_intent)intent);
345 } else {
346 #ifdef DEBUG_tor
347 fprintf(stderr, "ICM profile colorspace mismatch\n");
348 #endif
352 if (!mTransform) {
353 switch (mInfo.jpeg_color_space) {
354 case JCS_GRAYSCALE:
355 case JCS_RGB:
356 case JCS_YCbCr:
357 // if we're not color managing we can decode directly to
358 // MOZ_JCS_EXT_NATIVE_ENDIAN_XRGB
359 if (mCMSMode != eCMSMode_All) {
360 mInfo.out_color_space = MOZ_JCS_EXT_NATIVE_ENDIAN_XRGB;
361 mInfo.out_color_components = 4;
362 } else {
363 mInfo.out_color_space = JCS_RGB;
365 break;
366 case JCS_CMYK:
367 case JCS_YCCK:
368 /* libjpeg can convert from YCCK to CMYK, but not to RGB */
369 mInfo.out_color_space = JCS_CMYK;
370 break;
371 default:
372 mState = JPEG_ERROR;
373 PostDataError();
374 PR_LOG(GetJPEGDecoderAccountingLog(), PR_LOG_DEBUG,
375 ("} (unknown colorpsace (3))"));
376 return;
377 break;
382 * Don't allocate a giant and superfluous memory buffer
383 * when not doing a progressive decode.
385 mInfo.buffered_image = mDecodeStyle == PROGRESSIVE && jpeg_has_multiple_scans(&mInfo);
387 if (!mImageData) {
388 mState = JPEG_ERROR;
389 PostDecoderError(NS_ERROR_OUT_OF_MEMORY);
390 PR_LOG(GetJPEGDecoderAccountingLog(), PR_LOG_DEBUG,
391 ("} (could not initialize image frame)"));
392 return;
395 PR_LOG(GetJPEGDecoderAccountingLog(), PR_LOG_DEBUG,
396 (" JPEGDecoderAccounting: nsJPEGDecoder::Write -- created image frame with %ux%u pixels",
397 mInfo.output_width, mInfo.output_height));
399 mState = JPEG_START_DECOMPRESS;
402 case JPEG_START_DECOMPRESS:
404 LOG_SCOPE(GetJPEGLog(), "nsJPEGDecoder::Write -- entering JPEG_START_DECOMPRESS case");
405 /* Step 4: set parameters for decompression */
407 /* FIXME -- Should reset dct_method and dither mode
408 * for final pass of progressive JPEG
410 mInfo.dct_method = JDCT_ISLOW;
411 mInfo.dither_mode = JDITHER_FS;
412 mInfo.do_fancy_upsampling = TRUE;
413 mInfo.enable_2pass_quant = FALSE;
414 mInfo.do_block_smoothing = TRUE;
416 /* Step 5: Start decompressor */
417 if (jpeg_start_decompress(&mInfo) == FALSE) {
418 PR_LOG(GetJPEGDecoderAccountingLog(), PR_LOG_DEBUG,
419 ("} (I/O suspension after jpeg_start_decompress())"));
420 return; /* I/O suspension */
424 /* If this is a progressive JPEG ... */
425 mState = mInfo.buffered_image ? JPEG_DECOMPRESS_PROGRESSIVE : JPEG_DECOMPRESS_SEQUENTIAL;
428 case JPEG_DECOMPRESS_SEQUENTIAL:
430 if (mState == JPEG_DECOMPRESS_SEQUENTIAL)
432 LOG_SCOPE(GetJPEGLog(), "nsJPEGDecoder::Write -- JPEG_DECOMPRESS_SEQUENTIAL case");
434 bool suspend;
435 OutputScanlines(&suspend);
437 if (suspend) {
438 PR_LOG(GetJPEGDecoderAccountingLog(), PR_LOG_DEBUG,
439 ("} (I/O suspension after OutputScanlines() - SEQUENTIAL)"));
440 return; /* I/O suspension */
443 /* If we've completed image output ... */
444 NS_ASSERTION(mInfo.output_scanline == mInfo.output_height, "We didn't process all of the data!");
445 mState = JPEG_DONE;
449 case JPEG_DECOMPRESS_PROGRESSIVE:
451 if (mState == JPEG_DECOMPRESS_PROGRESSIVE)
453 LOG_SCOPE(GetJPEGLog(), "nsJPEGDecoder::Write -- JPEG_DECOMPRESS_PROGRESSIVE case");
455 int status;
456 do {
457 status = jpeg_consume_input(&mInfo);
458 } while ((status != JPEG_SUSPENDED) &&
459 (status != JPEG_REACHED_EOI));
461 for (;;) {
462 if (mInfo.output_scanline == 0) {
463 int scan = mInfo.input_scan_number;
465 /* if we haven't displayed anything yet (output_scan_number==0)
466 and we have enough data for a complete scan, force output
467 of the last full scan */
468 if ((mInfo.output_scan_number == 0) &&
469 (scan > 1) &&
470 (status != JPEG_REACHED_EOI))
471 scan--;
473 if (!jpeg_start_output(&mInfo, scan)) {
474 PR_LOG(GetJPEGDecoderAccountingLog(), PR_LOG_DEBUG,
475 ("} (I/O suspension after jpeg_start_output() - PROGRESSIVE)"));
476 return; /* I/O suspension */
480 if (mInfo.output_scanline == 0xffffff)
481 mInfo.output_scanline = 0;
483 bool suspend;
484 OutputScanlines(&suspend);
486 if (suspend) {
487 if (mInfo.output_scanline == 0) {
488 /* didn't manage to read any lines - flag so we don't call
489 jpeg_start_output() multiple times for the same scan */
490 mInfo.output_scanline = 0xffffff;
492 PR_LOG(GetJPEGDecoderAccountingLog(), PR_LOG_DEBUG,
493 ("} (I/O suspension after OutputScanlines() - PROGRESSIVE)"));
494 return; /* I/O suspension */
497 if (mInfo.output_scanline == mInfo.output_height)
499 if (!jpeg_finish_output(&mInfo)) {
500 PR_LOG(GetJPEGDecoderAccountingLog(), PR_LOG_DEBUG,
501 ("} (I/O suspension after jpeg_finish_output() - PROGRESSIVE)"));
502 return; /* I/O suspension */
505 if (jpeg_input_complete(&mInfo) &&
506 (mInfo.input_scan_number == mInfo.output_scan_number))
507 break;
509 mInfo.output_scanline = 0;
513 mState = JPEG_DONE;
517 case JPEG_DONE:
519 LOG_SCOPE(GetJPEGLog(), "nsJPEGDecoder::ProcessData -- entering JPEG_DONE case");
521 /* Step 7: Finish decompression */
523 if (jpeg_finish_decompress(&mInfo) == FALSE) {
524 PR_LOG(GetJPEGDecoderAccountingLog(), PR_LOG_DEBUG,
525 ("} (I/O suspension after jpeg_finish_decompress() - DONE)"));
526 return; /* I/O suspension */
529 mState = JPEG_SINK_NON_JPEG_TRAILER;
531 /* we're done dude */
532 break;
534 case JPEG_SINK_NON_JPEG_TRAILER:
535 PR_LOG(GetJPEGLog(), PR_LOG_DEBUG,
536 ("[this=%p] nsJPEGDecoder::ProcessData -- entering JPEG_SINK_NON_JPEG_TRAILER case\n", this));
538 break;
540 case JPEG_ERROR:
541 NS_ABORT_IF_FALSE(0, "Should always return immediately after error and not re-enter decoder");
544 PR_LOG(GetJPEGDecoderAccountingLog(), PR_LOG_DEBUG,
545 ("} (end of function)"));
546 return;
549 Orientation
550 nsJPEGDecoder::ReadOrientationFromEXIF()
552 jpeg_saved_marker_ptr marker;
554 // Locate the APP1 marker, where EXIF data is stored, in the marker list.
555 for (marker = mInfo.marker_list ; marker != nullptr ; marker = marker->next) {
556 if (marker->marker == JPEG_APP0 + 1)
557 break;
560 // If we're at the end of the list, there's no EXIF data.
561 if (!marker)
562 return Orientation();
564 // Extract the orientation information.
565 EXIFData exif = EXIFParser::Parse(marker->data,
566 static_cast<uint32_t>(marker->data_length));
567 return exif.orientation;
570 void
571 nsJPEGDecoder::NotifyDone()
573 PostFrameStop(FrameBlender::kFrameOpaque);
574 PostDecodeDone();
577 void
578 nsJPEGDecoder::OutputScanlines(bool* suspend)
580 *suspend = false;
582 const uint32_t top = mInfo.output_scanline;
584 while ((mInfo.output_scanline < mInfo.output_height)) {
585 /* Use the Cairo image buffer as scanline buffer */
586 uint32_t *imageRow = ((uint32_t*)mImageData) +
587 (mInfo.output_scanline * mInfo.output_width);
589 if (mInfo.out_color_space == MOZ_JCS_EXT_NATIVE_ENDIAN_XRGB) {
590 /* Special case: scanline will be directly converted into packed ARGB */
591 if (jpeg_read_scanlines(&mInfo, (JSAMPARRAY)&imageRow, 1) != 1) {
592 *suspend = true; /* suspend */
593 break;
595 continue; /* all done for this row! */
598 JSAMPROW sampleRow = (JSAMPROW)imageRow;
599 if (mInfo.output_components == 3) {
600 /* Put the pixels at end of row to enable in-place expansion */
601 sampleRow += mInfo.output_width;
604 /* Request one scanline. Returns 0 or 1 scanlines. */
605 if (jpeg_read_scanlines(&mInfo, &sampleRow, 1) != 1) {
606 *suspend = true; /* suspend */
607 break;
610 if (mTransform) {
611 JSAMPROW source = sampleRow;
612 if (mInfo.out_color_space == JCS_GRAYSCALE) {
613 /* Convert from the 1byte grey pixels at begin of row
614 to the 3byte RGB byte pixels at 'end' of row */
615 sampleRow += mInfo.output_width;
617 qcms_transform_data(mTransform, source, sampleRow, mInfo.output_width);
618 /* Move 3byte RGB data to end of row */
619 if (mInfo.out_color_space == JCS_CMYK) {
620 memmove(sampleRow + mInfo.output_width,
621 sampleRow,
622 3 * mInfo.output_width);
623 sampleRow += mInfo.output_width;
625 } else {
626 if (mInfo.out_color_space == JCS_CMYK) {
627 /* Convert from CMYK to RGB */
628 /* We cannot convert directly to Cairo, as the CMSRGBTransform may wants to do a RGB transform... */
629 /* Would be better to have platform CMSenabled transformation from CMYK to (A)RGB... */
630 cmyk_convert_rgb((JSAMPROW)imageRow, mInfo.output_width);
631 sampleRow += mInfo.output_width;
633 if (mCMSMode == eCMSMode_All) {
634 /* No embedded ICC profile - treat as sRGB */
635 qcms_transform *transform = gfxPlatform::GetCMSRGBTransform();
636 if (transform) {
637 qcms_transform_data(transform, sampleRow, sampleRow, mInfo.output_width);
642 // counter for while() loops below
643 uint32_t idx = mInfo.output_width;
645 // copy as bytes until source pointer is 32-bit-aligned
646 for (; (NS_PTR_TO_UINT32(sampleRow) & 0x3) && idx; --idx) {
647 *imageRow++ = gfxPackedPixel(0xFF, sampleRow[0], sampleRow[1], sampleRow[2]);
648 sampleRow += 3;
651 // copy pixels in blocks of 4
652 while (idx >= 4) {
653 GFX_BLOCK_RGB_TO_FRGB(sampleRow, imageRow);
654 idx -= 4;
655 sampleRow += 12;
656 imageRow += 4;
659 // copy remaining pixel(s)
660 while (idx--) {
661 // 32-bit read of final pixel will exceed buffer, so read bytes
662 *imageRow++ = gfxPackedPixel(0xFF, sampleRow[0], sampleRow[1], sampleRow[2]);
663 sampleRow += 3;
667 if (top != mInfo.output_scanline) {
668 nsIntRect r(0, top, mInfo.output_width, mInfo.output_scanline-top);
669 PostInvalidation(r);
675 /* Override the standard error method in the IJG JPEG decoder code. */
676 METHODDEF(void)
677 my_error_exit (j_common_ptr cinfo)
679 decoder_error_mgr *err = (decoder_error_mgr *) cinfo->err;
681 /* Convert error to a browser error code */
682 nsresult error_code = err->pub.msg_code == JERR_OUT_OF_MEMORY
683 ? NS_ERROR_OUT_OF_MEMORY
684 : NS_ERROR_FAILURE;
686 #ifdef DEBUG
687 char buffer[JMSG_LENGTH_MAX];
689 /* Create the message */
690 (*err->pub.format_message) (cinfo, buffer);
692 fprintf(stderr, "JPEG decoding error:\n%s\n", buffer);
693 #endif
695 /* Return control to the setjmp point. We pass an nsresult masquerading as
696 * an int, which works because the setjmp() caller casts it back. */
697 longjmp(err->setjmp_buffer, static_cast<int>(error_code));
700 /******************************************************************************/
701 /*-----------------------------------------------------------------------------
702 * This is the callback routine from the IJG JPEG library used to supply new
703 * data to the decompressor when its input buffer is exhausted. It juggles
704 * multiple buffers in an attempt to avoid unnecessary copying of input data.
706 * (A simpler scheme is possible: It's much easier to use only a single
707 * buffer; when fill_input_buffer() is called, move any unconsumed data
708 * (beyond the current pointer/count) down to the beginning of this buffer and
709 * then load new data into the remaining buffer space. This approach requires
710 * a little more data copying but is far easier to get right.)
712 * At any one time, the JPEG decompressor is either reading from the necko
713 * input buffer, which is volatile across top-level calls to the IJG library,
714 * or the "backtrack" buffer. The backtrack buffer contains the remaining
715 * unconsumed data from the necko buffer after parsing was suspended due
716 * to insufficient data in some previous call to the IJG library.
718 * When suspending, the decompressor will back up to a convenient restart
719 * point (typically the start of the current MCU). The variables
720 * next_input_byte & bytes_in_buffer indicate where the restart point will be
721 * if the current call returns FALSE. Data beyond this point must be
722 * rescanned after resumption, so it must be preserved in case the decompressor
723 * decides to backtrack.
725 * Returns:
726 * TRUE if additional data is available, FALSE if no data present and
727 * the JPEG library should therefore suspend processing of input stream
728 *---------------------------------------------------------------------------*/
730 /******************************************************************************/
731 /* data source manager method */
732 /******************************************************************************/
735 /******************************************************************************/
736 /* data source manager method
737 Initialize source. This is called by jpeg_read_header() before any
738 data is actually read. May leave
739 bytes_in_buffer set to 0 (in which case a fill_input_buffer() call
740 will occur immediately).
742 METHODDEF(void)
743 init_source (j_decompress_ptr jd)
747 /******************************************************************************/
748 /* data source manager method
749 Skip num_bytes worth of data. The buffer pointer and count should
750 be advanced over num_bytes input bytes, refilling the buffer as
751 needed. This is used to skip over a potentially large amount of
752 uninteresting data (such as an APPn marker). In some applications
753 it may be possible to optimize away the reading of the skipped data,
754 but it's not clear that being smart is worth much trouble; large
755 skips are uncommon. bytes_in_buffer may be zero on return.
756 A zero or negative skip count should be treated as a no-op.
758 METHODDEF(void)
759 skip_input_data (j_decompress_ptr jd, long num_bytes)
761 struct jpeg_source_mgr *src = jd->src;
762 nsJPEGDecoder *decoder = (nsJPEGDecoder *)(jd->client_data);
764 if (num_bytes > (long)src->bytes_in_buffer) {
766 * Can't skip it all right now until we get more data from
767 * network stream. Set things up so that fill_input_buffer
768 * will skip remaining amount.
770 decoder->mBytesToSkip = (size_t)num_bytes - src->bytes_in_buffer;
771 src->next_input_byte += src->bytes_in_buffer;
772 src->bytes_in_buffer = 0;
774 } else {
775 /* Simple case. Just advance buffer pointer */
777 src->bytes_in_buffer -= (size_t)num_bytes;
778 src->next_input_byte += num_bytes;
783 /******************************************************************************/
784 /* data source manager method
785 This is called whenever bytes_in_buffer has reached zero and more
786 data is wanted. In typical applications, it should read fresh data
787 into the buffer (ignoring the current state of next_input_byte and
788 bytes_in_buffer), reset the pointer & count to the start of the
789 buffer, and return TRUE indicating that the buffer has been reloaded.
790 It is not necessary to fill the buffer entirely, only to obtain at
791 least one more byte. bytes_in_buffer MUST be set to a positive value
792 if TRUE is returned. A FALSE return should only be used when I/O
793 suspension is desired.
795 METHODDEF(boolean)
796 fill_input_buffer (j_decompress_ptr jd)
798 struct jpeg_source_mgr *src = jd->src;
799 nsJPEGDecoder *decoder = (nsJPEGDecoder *)(jd->client_data);
801 if (decoder->mReading) {
802 const JOCTET *new_buffer = decoder->mSegment;
803 uint32_t new_buflen = decoder->mSegmentLen;
805 if (!new_buffer || new_buflen == 0)
806 return false; /* suspend */
808 decoder->mSegmentLen = 0;
810 if (decoder->mBytesToSkip) {
811 if (decoder->mBytesToSkip < new_buflen) {
812 /* All done skipping bytes; Return what's left. */
813 new_buffer += decoder->mBytesToSkip;
814 new_buflen -= decoder->mBytesToSkip;
815 decoder->mBytesToSkip = 0;
816 } else {
817 /* Still need to skip some more data in the future */
818 decoder->mBytesToSkip -= (size_t)new_buflen;
819 return false; /* suspend */
823 decoder->mBackBufferUnreadLen = src->bytes_in_buffer;
825 src->next_input_byte = new_buffer;
826 src->bytes_in_buffer = (size_t)new_buflen;
827 decoder->mReading = false;
829 return true;
832 if (src->next_input_byte != decoder->mSegment) {
833 /* Backtrack data has been permanently consumed. */
834 decoder->mBackBufferUnreadLen = 0;
835 decoder->mBackBufferLen = 0;
838 /* Save remainder of netlib buffer in backtrack buffer */
839 const uint32_t new_backtrack_buflen = src->bytes_in_buffer + decoder->mBackBufferLen;
841 /* Make sure backtrack buffer is big enough to hold new data. */
842 if (decoder->mBackBufferSize < new_backtrack_buflen) {
843 /* Check for malformed MARKER segment lengths, before allocating space for it */
844 if (new_backtrack_buflen > MAX_JPEG_MARKER_LENGTH) {
845 my_error_exit((j_common_ptr)(&decoder->mInfo));
848 /* Round up to multiple of 256 bytes. */
849 const size_t roundup_buflen = ((new_backtrack_buflen + 255) >> 8) << 8;
850 JOCTET *buf = (JOCTET *)PR_REALLOC(decoder->mBackBuffer, roundup_buflen);
851 /* Check for OOM */
852 if (!buf) {
853 decoder->mInfo.err->msg_code = JERR_OUT_OF_MEMORY;
854 my_error_exit((j_common_ptr)(&decoder->mInfo));
856 decoder->mBackBuffer = buf;
857 decoder->mBackBufferSize = roundup_buflen;
860 /* Copy remainder of netlib segment into backtrack buffer. */
861 memmove(decoder->mBackBuffer + decoder->mBackBufferLen,
862 src->next_input_byte,
863 src->bytes_in_buffer);
865 /* Point to start of data to be rescanned. */
866 src->next_input_byte = decoder->mBackBuffer + decoder->mBackBufferLen - decoder->mBackBufferUnreadLen;
867 src->bytes_in_buffer += decoder->mBackBufferUnreadLen;
868 decoder->mBackBufferLen = (size_t)new_backtrack_buflen;
869 decoder->mReading = true;
871 return false;
874 /******************************************************************************/
875 /* data source manager method */
877 * Terminate source --- called by jpeg_finish_decompress() after all
878 * data has been read to clean up JPEG source manager. NOT called by
879 * jpeg_abort() or jpeg_destroy().
881 METHODDEF(void)
882 term_source (j_decompress_ptr jd)
884 nsJPEGDecoder *decoder = (nsJPEGDecoder *)(jd->client_data);
886 // This function shouldn't be called if we ran into an error we didn't
887 // recover from.
888 NS_ABORT_IF_FALSE(decoder->mState != JPEG_ERROR,
889 "Calling term_source on a JPEG with mState == JPEG_ERROR!");
891 // Notify using a helper method to get around protectedness issues.
892 decoder->NotifyDone();
895 } // namespace image
896 } // namespace mozilla
899 /**************** Inverted CMYK -> RGB conversion **************/
901 * Input is (Inverted) CMYK stored as 4 bytes per pixel.
902 * Output is RGB stored as 3 bytes per pixel.
903 * @param row Points to row buffer containing the CMYK bytes for each pixel in the row.
904 * @param width Number of pixels in the row.
906 static void cmyk_convert_rgb(JSAMPROW row, JDIMENSION width)
908 /* Work from end to front to shrink from 4 bytes per pixel to 3 */
909 JSAMPROW in = row + width*4;
910 JSAMPROW out = in;
912 for (uint32_t i = width; i > 0; i--) {
913 in -= 4;
914 out -= 3;
916 // Source is 'Inverted CMYK', output is RGB.
917 // See: http://www.easyrgb.com/math.php?MATH=M12#text12
918 // Or: http://www.ilkeratalay.com/colorspacesfaq.php#rgb
920 // From CMYK to CMY
921 // C = ( C * ( 1 - K ) + K )
922 // M = ( M * ( 1 - K ) + K )
923 // Y = ( Y * ( 1 - K ) + K )
925 // From Inverted CMYK to CMY is thus:
926 // C = ( (1-iC) * (1 - (1-iK)) + (1-iK) ) => 1 - iC*iK
927 // Same for M and Y
929 // Convert from CMY (0..1) to RGB (0..1)
930 // R = 1 - C => 1 - (1 - iC*iK) => iC*iK
931 // G = 1 - M => 1 - (1 - iM*iK) => iM*iK
932 // B = 1 - Y => 1 - (1 - iY*iK) => iY*iK
934 // Convert from Inverted CMYK (0..255) to RGB (0..255)
935 const uint32_t iC = in[0];
936 const uint32_t iM = in[1];
937 const uint32_t iY = in[2];
938 const uint32_t iK = in[3];
939 out[0] = iC*iK/255; // Red
940 out[1] = iM*iK/255; // Green
941 out[2] = iY*iK/255; // Blue