image/decoders/nsJPEGDecoder.cpp

branch
TOR_BUG_9701
changeset 10
ac0c01689b40
equal deleted inserted replaced
-1:000000000000 0:1d102ef5c0e4
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"
8 #include "nsJPEGDecoder.h"
9 #include "Orientation.h"
10 #include "EXIF.h"
11
12 #include "nsIInputStream.h"
13
14 #include "nspr.h"
15 #include "nsCRT.h"
16 #include "gfxColor.h"
17
18 #include "jerror.h"
19
20 #include "gfxPlatform.h"
21
22 extern "C" {
23 #include "iccjpeg.h"
24 }
25
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
31
32 static void cmyk_convert_rgb(JSAMPROW row, JDIMENSION width);
33
34 namespace mozilla {
35 namespace image {
36
37 #if defined(PR_LOGGING)
38 static PRLogModuleInfo *
39 GetJPEGLog()
40 {
41 static PRLogModuleInfo *sJPEGLog;
42 if (!sJPEGLog)
43 sJPEGLog = PR_NewLogModule("JPEGDecoder");
44 return sJPEGLog;
45 }
46
47 static PRLogModuleInfo *
48 GetJPEGDecoderAccountingLog()
49 {
50 static PRLogModuleInfo *sJPEGDecoderAccountingLog;
51 if (!sJPEGDecoderAccountingLog)
52 sJPEGDecoderAccountingLog = PR_NewLogModule("JPEGDecoderAccounting");
53 return sJPEGDecoderAccountingLog;
54 }
55 #else
56 #define GetJPEGLog()
57 #define GetJPEGDecoderAccountingLog()
58 #endif
59
60 static qcms_profile*
61 GetICCProfile(struct jpeg_decompress_struct &info)
62 {
63 JOCTET* profilebuf;
64 uint32_t profileLength;
65 qcms_profile* profile = nullptr;
66
67 if (read_icc_profile(&info, &profilebuf, &profileLength)) {
68 profile = qcms_profile_from_memory(profilebuf, profileLength);
69 free(profilebuf);
70 }
71
72 return profile;
73 }
74
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);
80
81 /* Normal JFIF markers can't have more bytes than this. */
82 #define MAX_JPEG_MARKER_LENGTH (((uint32_t)1 << 16) - 1)
83
84
85 nsJPEGDecoder::nsJPEGDecoder(RasterImage& aImage, Decoder::DecodeStyle aDecodeStyle)
86 : Decoder(aImage)
87 , mDecodeStyle(aDecodeStyle)
88 {
89 mState = JPEG_HEADER;
90 mReading = true;
91 mImageData = nullptr;
92
93 mBytesToSkip = 0;
94 memset(&mInfo, 0, sizeof(jpeg_decompress_struct));
95 memset(&mSourceMgr, 0, sizeof(mSourceMgr));
96 mInfo.client_data = (void*)this;
97
98 mSegment = nullptr;
99 mSegmentLen = 0;
100
101 mBackBuffer = nullptr;
102 mBackBufferLen = mBackBufferSize = mBackBufferUnreadLen = 0;
103
104 mInProfile = nullptr;
105 mTransform = nullptr;
106
107 mCMSMode = 0;
108
109 PR_LOG(GetJPEGDecoderAccountingLog(), PR_LOG_DEBUG,
110 ("nsJPEGDecoder::nsJPEGDecoder: Creating JPEG decoder %p",
111 this));
112 }
113
114 nsJPEGDecoder::~nsJPEGDecoder()
115 {
116 // Step 8: Release JPEG decompression object
117 mInfo.src = nullptr;
118 jpeg_destroy_decompress(&mInfo);
119
120 PR_FREEIF(mBackBuffer);
121 if (mTransform)
122 qcms_transform_release(mTransform);
123 if (mInProfile)
124 qcms_profile_release(mInProfile);
125
126 PR_LOG(GetJPEGDecoderAccountingLog(), PR_LOG_DEBUG,
127 ("nsJPEGDecoder::~nsJPEGDecoder: Destroying JPEG decoder %p",
128 this));
129 }
130
131 Telemetry::ID
132 nsJPEGDecoder::SpeedHistogram()
133 {
134 return Telemetry::IMAGE_DECODE_SPEED_JPEG;
135 }
136
137 void
138 nsJPEGDecoder::InitInternal()
139 {
140 mCMSMode = gfxPlatform::GetCMSMode();
141 if ((mDecodeFlags & DECODER_NO_COLORSPACE_CONVERSION) != 0)
142 mCMSMode = eCMSMode_Off;
143
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.
152 */
153 PostDecoderError(NS_ERROR_FAILURE);
154 return;
155 }
156
157 /* Step 1: allocate and initialize JPEG decompression object */
158 jpeg_create_decompress(&mInfo);
159 /* Set the source manager */
160 mInfo.src = &mSourceMgr;
161
162 /* Step 2: specify data source (eg, a file) */
163
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;
170
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);
174 }
175
176 void
177 nsJPEGDecoder::FinishInternal()
178 {
179 /* If we're not in any sort of error case, flush the decoder.
180 *
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.
184 *
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.)
189 */
190 if ((mState != JPEG_DONE && mState != JPEG_SINK_NON_JPEG_TRAILER) &&
191 (mState != JPEG_ERROR) &&
192 !IsSizeDecode())
193 this->Write(nullptr, 0, DECODE_SYNC);
194 }
195
196 void
197 nsJPEGDecoder::WriteInternal(const char *aBuffer, uint32_t aCount, DecodeStrategy)
198 {
199 mSegment = (const JOCTET *)aBuffer;
200 mSegmentLen = aCount;
201
202 NS_ABORT_IF_FALSE(!HasError(), "Shouldn't call WriteInternal after error!");
203
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;
226 }
227 }
228
229 PR_LOG(GetJPEGLog(), PR_LOG_DEBUG,
230 ("[this=%p] nsJPEGDecoder::Write -- processing JPEG data\n", this));
231
232 switch (mState) {
233 case JPEG_HEADER:
234 {
235 LOG_SCOPE(GetJPEGLog(), "nsJPEGDecoder::Write -- entering JPEG_HEADER case");
236
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 */
242 }
243
244 int sampleSize = mImage.GetRequestedSampleSize();
245 if (sampleSize > 0) {
246 mInfo.scale_num = 1;
247 mInfo.scale_denom = sampleSize;
248 }
249
250 /* Used to set up image size so arrays can be allocated */
251 jpeg_calc_output_dimensions(&mInfo);
252
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;
259 }
260
261 /* If we're doing a size decode, we're done. */
262 if (IsSizeDecode())
263 return;
264
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;
270
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;
303 }
304
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;
320 }
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.
325 */
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
330
331 if (gfxPlatform::GetCMSOutputProfile()) {
332
333 /* Calculate rendering intent. */
334 int intent = gfxPlatform::GetRenderingIntent();
335 if (intent == -1)
336 intent = qcms_profile_get_rendering_intent(mInProfile);
337
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);
344 }
345 } else {
346 #ifdef DEBUG_tor
347 fprintf(stderr, "ICM profile colorspace mismatch\n");
348 #endif
349 }
350 }
351
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;
364 }
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;
378 }
379 }
380
381 /*
382 * Don't allocate a giant and superfluous memory buffer
383 * when not doing a progressive decode.
384 */
385 mInfo.buffered_image = mDecodeStyle == PROGRESSIVE && jpeg_has_multiple_scans(&mInfo);
386
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;
393 }
394
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));
398
399 mState = JPEG_START_DECOMPRESS;
400 }
401
402 case JPEG_START_DECOMPRESS:
403 {
404 LOG_SCOPE(GetJPEGLog(), "nsJPEGDecoder::Write -- entering JPEG_START_DECOMPRESS case");
405 /* Step 4: set parameters for decompression */
406
407 /* FIXME -- Should reset dct_method and dither mode
408 * for final pass of progressive JPEG
409 */
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;
415
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 */
421 }
422
423
424 /* If this is a progressive JPEG ... */
425 mState = mInfo.buffered_image ? JPEG_DECOMPRESS_PROGRESSIVE : JPEG_DECOMPRESS_SEQUENTIAL;
426 }
427
428 case JPEG_DECOMPRESS_SEQUENTIAL:
429 {
430 if (mState == JPEG_DECOMPRESS_SEQUENTIAL)
431 {
432 LOG_SCOPE(GetJPEGLog(), "nsJPEGDecoder::Write -- JPEG_DECOMPRESS_SEQUENTIAL case");
433
434 bool suspend;
435 OutputScanlines(&suspend);
436
437 if (suspend) {
438 PR_LOG(GetJPEGDecoderAccountingLog(), PR_LOG_DEBUG,
439 ("} (I/O suspension after OutputScanlines() - SEQUENTIAL)"));
440 return; /* I/O suspension */
441 }
442
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;
446 }
447 }
448
449 case JPEG_DECOMPRESS_PROGRESSIVE:
450 {
451 if (mState == JPEG_DECOMPRESS_PROGRESSIVE)
452 {
453 LOG_SCOPE(GetJPEGLog(), "nsJPEGDecoder::Write -- JPEG_DECOMPRESS_PROGRESSIVE case");
454
455 int status;
456 do {
457 status = jpeg_consume_input(&mInfo);
458 } while ((status != JPEG_SUSPENDED) &&
459 (status != JPEG_REACHED_EOI));
460
461 for (;;) {
462 if (mInfo.output_scanline == 0) {
463 int scan = mInfo.input_scan_number;
464
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--;
472
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 */
477 }
478 }
479
480 if (mInfo.output_scanline == 0xffffff)
481 mInfo.output_scanline = 0;
482
483 bool suspend;
484 OutputScanlines(&suspend);
485
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;
491 }
492 PR_LOG(GetJPEGDecoderAccountingLog(), PR_LOG_DEBUG,
493 ("} (I/O suspension after OutputScanlines() - PROGRESSIVE)"));
494 return; /* I/O suspension */
495 }
496
497 if (mInfo.output_scanline == mInfo.output_height)
498 {
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 */
503 }
504
505 if (jpeg_input_complete(&mInfo) &&
506 (mInfo.input_scan_number == mInfo.output_scan_number))
507 break;
508
509 mInfo.output_scanline = 0;
510 }
511 }
512
513 mState = JPEG_DONE;
514 }
515 }
516
517 case JPEG_DONE:
518 {
519 LOG_SCOPE(GetJPEGLog(), "nsJPEGDecoder::ProcessData -- entering JPEG_DONE case");
520
521 /* Step 7: Finish decompression */
522
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 */
527 }
528
529 mState = JPEG_SINK_NON_JPEG_TRAILER;
530
531 /* we're done dude */
532 break;
533 }
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));
537
538 break;
539
540 case JPEG_ERROR:
541 NS_ABORT_IF_FALSE(0, "Should always return immediately after error and not re-enter decoder");
542 }
543
544 PR_LOG(GetJPEGDecoderAccountingLog(), PR_LOG_DEBUG,
545 ("} (end of function)"));
546 return;
547 }
548
549 Orientation
550 nsJPEGDecoder::ReadOrientationFromEXIF()
551 {
552 jpeg_saved_marker_ptr marker;
553
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;
558 }
559
560 // If we're at the end of the list, there's no EXIF data.
561 if (!marker)
562 return Orientation();
563
564 // Extract the orientation information.
565 EXIFData exif = EXIFParser::Parse(marker->data,
566 static_cast<uint32_t>(marker->data_length));
567 return exif.orientation;
568 }
569
570 void
571 nsJPEGDecoder::NotifyDone()
572 {
573 PostFrameStop(FrameBlender::kFrameOpaque);
574 PostDecodeDone();
575 }
576
577 void
578 nsJPEGDecoder::OutputScanlines(bool* suspend)
579 {
580 *suspend = false;
581
582 const uint32_t top = mInfo.output_scanline;
583
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);
588
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;
594 }
595 continue; /* all done for this row! */
596 }
597
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;
602 }
603
604 /* Request one scanline. Returns 0 or 1 scanlines. */
605 if (jpeg_read_scanlines(&mInfo, &sampleRow, 1) != 1) {
606 *suspend = true; /* suspend */
607 break;
608 }
609
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;
616 }
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;
624 }
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;
632 }
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);
638 }
639 }
640 }
641
642 // counter for while() loops below
643 uint32_t idx = mInfo.output_width;
644
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;
649 }
650
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;
657 }
658
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;
664 }
665 }
666
667 if (top != mInfo.output_scanline) {
668 nsIntRect r(0, top, mInfo.output_width, mInfo.output_scanline-top);
669 PostInvalidation(r);
670 }
671
672 }
673
674
675 /* Override the standard error method in the IJG JPEG decoder code. */
676 METHODDEF(void)
677 my_error_exit (j_common_ptr cinfo)
678 {
679 decoder_error_mgr *err = (decoder_error_mgr *) cinfo->err;
680
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;
685
686 #ifdef DEBUG
687 char buffer[JMSG_LENGTH_MAX];
688
689 /* Create the message */
690 (*err->pub.format_message) (cinfo, buffer);
691
692 fprintf(stderr, "JPEG decoding error:\n%s\n", buffer);
693 #endif
694
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));
698 }
699
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.
705 *
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.)
711 *
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.
717 *
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.
724 *
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 *---------------------------------------------------------------------------*/
729
730 /******************************************************************************/
731 /* data source manager method */
732 /******************************************************************************/
733
734
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).
741 */
742 METHODDEF(void)
743 init_source (j_decompress_ptr jd)
744 {
745 }
746
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.
757 */
758 METHODDEF(void)
759 skip_input_data (j_decompress_ptr jd, long num_bytes)
760 {
761 struct jpeg_source_mgr *src = jd->src;
762 nsJPEGDecoder *decoder = (nsJPEGDecoder *)(jd->client_data);
763
764 if (num_bytes > (long)src->bytes_in_buffer) {
765 /*
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.
769 */
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;
773
774 } else {
775 /* Simple case. Just advance buffer pointer */
776
777 src->bytes_in_buffer -= (size_t)num_bytes;
778 src->next_input_byte += num_bytes;
779 }
780 }
781
782
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.
794 */
795 METHODDEF(boolean)
796 fill_input_buffer (j_decompress_ptr jd)
797 {
798 struct jpeg_source_mgr *src = jd->src;
799 nsJPEGDecoder *decoder = (nsJPEGDecoder *)(jd->client_data);
800
801 if (decoder->mReading) {
802 const JOCTET *new_buffer = decoder->mSegment;
803 uint32_t new_buflen = decoder->mSegmentLen;
804
805 if (!new_buffer || new_buflen == 0)
806 return false; /* suspend */
807
808 decoder->mSegmentLen = 0;
809
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 */
820 }
821 }
822
823 decoder->mBackBufferUnreadLen = src->bytes_in_buffer;
824
825 src->next_input_byte = new_buffer;
826 src->bytes_in_buffer = (size_t)new_buflen;
827 decoder->mReading = false;
828
829 return true;
830 }
831
832 if (src->next_input_byte != decoder->mSegment) {
833 /* Backtrack data has been permanently consumed. */
834 decoder->mBackBufferUnreadLen = 0;
835 decoder->mBackBufferLen = 0;
836 }
837
838 /* Save remainder of netlib buffer in backtrack buffer */
839 const uint32_t new_backtrack_buflen = src->bytes_in_buffer + decoder->mBackBufferLen;
840
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));
846 }
847
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));
855 }
856 decoder->mBackBuffer = buf;
857 decoder->mBackBufferSize = roundup_buflen;
858 }
859
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);
864
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;
870
871 return false;
872 }
873
874 /******************************************************************************/
875 /* data source manager method */
876 /*
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().
880 */
881 METHODDEF(void)
882 term_source (j_decompress_ptr jd)
883 {
884 nsJPEGDecoder *decoder = (nsJPEGDecoder *)(jd->client_data);
885
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!");
890
891 // Notify using a helper method to get around protectedness issues.
892 decoder->NotifyDone();
893 }
894
895 } // namespace image
896 } // namespace mozilla
897
898
899 /**************** Inverted CMYK -> RGB conversion **************/
900 /*
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.
905 */
906 static void cmyk_convert_rgb(JSAMPROW row, JDIMENSION width)
907 {
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;
911
912 for (uint32_t i = width; i > 0; i--) {
913 in -= 4;
914 out -= 3;
915
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
919
920 // From CMYK to CMY
921 // C = ( C * ( 1 - K ) + K )
922 // M = ( M * ( 1 - K ) + K )
923 // Y = ( Y * ( 1 - K ) + K )
924
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
928
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
933
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
942 }
943 }

mercurial