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" // Must appear first.
9 #include "nsJPEGDecoder.h"
14 #include "Orientation.h"
16 #include "SurfacePipeFactory.h"
24 #include "gfxPlatform.h"
25 #include "mozilla/EndianUtils.h"
26 #include "mozilla/gfx/Types.h"
27 #include "mozilla/Telemetry.h"
34 # define MOZ_JCS_EXT_NATIVE_ENDIAN_XRGB JCS_EXT_XRGB
36 # define MOZ_JCS_EXT_NATIVE_ENDIAN_XRGB JCS_EXT_BGRX
39 static void cmyk_convert_bgra(uint32_t* aInput
, uint32_t* aOutput
,
42 using mozilla::gfx::SurfaceFormat
;
47 static mozilla::LazyLogModule
sJPEGLog("JPEGDecoder");
49 static mozilla::LazyLogModule
sJPEGDecoderAccountingLog(
50 "JPEGDecoderAccounting");
52 static qcms_profile
* GetICCProfile(struct jpeg_decompress_struct
& info
) {
54 uint32_t profileLength
;
55 qcms_profile
* profile
= nullptr;
57 if (read_icc_profile(&info
, &profilebuf
, &profileLength
)) {
58 profile
= qcms_profile_from_memory(profilebuf
, profileLength
);
65 METHODDEF(void) init_source(j_decompress_ptr jd
);
66 METHODDEF(boolean
) fill_input_buffer(j_decompress_ptr jd
);
67 METHODDEF(void) skip_input_data(j_decompress_ptr jd
, long num_bytes
);
68 METHODDEF(void) term_source(j_decompress_ptr jd
);
69 METHODDEF(void) my_error_exit(j_common_ptr cinfo
);
71 // Normal JFIF markers can't have more bytes than this.
72 #define MAX_JPEG_MARKER_LENGTH (((uint32_t)1 << 16) - 1)
74 nsJPEGDecoder::nsJPEGDecoder(RasterImage
* aImage
,
75 Decoder::DecodeStyle aDecodeStyle
)
77 mLexer(Transition::ToUnbuffered(State::FINISHED_JPEG_DATA
,
78 State::JPEG_DATA
, SIZE_MAX
),
79 Transition::TerminateSuccess()),
83 mDecodeStyle(aDecodeStyle
) {
84 this->mErr
.pub
.error_exit
= nullptr;
85 this->mErr
.pub
.emit_message
= nullptr;
86 this->mErr
.pub
.output_message
= nullptr;
87 this->mErr
.pub
.format_message
= nullptr;
88 this->mErr
.pub
.reset_error_mgr
= nullptr;
89 this->mErr
.pub
.msg_code
= 0;
90 this->mErr
.pub
.trace_level
= 0;
91 this->mErr
.pub
.num_warnings
= 0;
92 this->mErr
.pub
.jpeg_message_table
= nullptr;
93 this->mErr
.pub
.last_jpeg_message
= 0;
94 this->mErr
.pub
.addon_message_table
= nullptr;
95 this->mErr
.pub
.first_addon_message
= 0;
96 this->mErr
.pub
.last_addon_message
= 0;
102 memset(&mInfo
, 0, sizeof(jpeg_decompress_struct
));
103 memset(&mSourceMgr
, 0, sizeof(mSourceMgr
));
104 mInfo
.client_data
= (void*)this;
109 mBackBuffer
= nullptr;
110 mBackBufferLen
= mBackBufferSize
= mBackBufferUnreadLen
= 0;
112 MOZ_LOG(sJPEGDecoderAccountingLog
, LogLevel::Debug
,
113 ("nsJPEGDecoder::nsJPEGDecoder: Creating JPEG decoder %p", this));
116 nsJPEGDecoder::~nsJPEGDecoder() {
117 // Step 8: Release JPEG decompression object
119 jpeg_destroy_decompress(&mInfo
);
122 mBackBuffer
= nullptr;
126 MOZ_LOG(sJPEGDecoderAccountingLog
, LogLevel::Debug
,
127 ("nsJPEGDecoder::~nsJPEGDecoder: Destroying JPEG decoder %p", this));
130 Maybe
<Telemetry::HistogramID
> nsJPEGDecoder::SpeedHistogram() const {
131 return Some(Telemetry::IMAGE_DECODE_SPEED_JPEG
);
134 nsresult
nsJPEGDecoder::InitInternal() {
135 // We set up the normal JPEG error routines, then override error_exit.
136 mInfo
.err
= jpeg_std_error(&mErr
.pub
);
137 // mInfo.err = jpeg_std_error(&mErr.pub);
138 mErr
.pub
.error_exit
= my_error_exit
;
139 // Establish the setjmp return context for my_error_exit to use.
140 if (setjmp(mErr
.setjmp_buffer
)) {
141 // If we get here, the JPEG code has signaled an error, and initialization
143 return NS_ERROR_FAILURE
;
146 // Step 1: allocate and initialize JPEG decompression object
147 jpeg_create_decompress(&mInfo
);
148 // Set the source manager
149 mInfo
.src
= &mSourceMgr
;
151 // Step 2: specify data source (eg, a file)
153 // Setup callback functions.
154 mSourceMgr
.init_source
= init_source
;
155 mSourceMgr
.fill_input_buffer
= fill_input_buffer
;
156 mSourceMgr
.skip_input_data
= skip_input_data
;
157 mSourceMgr
.resync_to_restart
= jpeg_resync_to_restart
;
158 mSourceMgr
.term_source
= term_source
;
160 // Record app markers for ICC data
161 for (uint32_t m
= 0; m
< 16; m
++) {
162 jpeg_save_markers(&mInfo
, JPEG_APP0
+ m
, 0xFFFF);
168 nsresult
nsJPEGDecoder::FinishInternal() {
169 // If we're not in any sort of error case, force our state to JPEG_DONE.
170 if ((mState
!= JPEG_DONE
&& mState
!= JPEG_SINK_NON_JPEG_TRAILER
) &&
171 (mState
!= JPEG_ERROR
) && !IsMetadataDecode()) {
178 LexerResult
nsJPEGDecoder::DoDecode(SourceBufferIterator
& aIterator
,
179 IResumable
* aOnResume
) {
180 MOZ_ASSERT(!HasError(), "Shouldn't call DoDecode after error!");
182 return mLexer
.Lex(aIterator
, aOnResume
,
183 [=](State aState
, const char* aData
, size_t aLength
) {
185 case State::JPEG_DATA
:
186 return ReadJPEGData(aData
, aLength
);
187 case State::FINISHED_JPEG_DATA
:
188 return FinishedJPEGData();
190 MOZ_CRASH("Unknown State");
194 LexerTransition
<nsJPEGDecoder::State
> nsJPEGDecoder::ReadJPEGData(
195 const char* aData
, size_t aLength
) {
196 mSegment
= reinterpret_cast<const JOCTET
*>(aData
);
197 mSegmentLen
= aLength
;
199 // Return here if there is a fatal error within libjpeg.
201 // This cast to nsresult makes sense because setjmp() returns whatever we
202 // passed to longjmp(), which was actually an nsresult.
203 if ((error_code
= static_cast<nsresult
>(setjmp(mErr
.setjmp_buffer
))) !=
205 if (error_code
== NS_ERROR_FAILURE
) {
206 // Error due to corrupt data. Make sure that we don't feed any more data
208 mState
= JPEG_SINK_NON_JPEG_TRAILER
;
209 MOZ_LOG(sJPEGDecoderAccountingLog
, LogLevel::Debug
,
210 ("} (setjmp returned NS_ERROR_FAILURE)"));
212 // Error for another reason. (Possibly OOM.)
214 MOZ_LOG(sJPEGDecoderAccountingLog
, LogLevel::Debug
,
215 ("} (setjmp returned an error)"));
218 return Transition::TerminateFailure();
221 MOZ_LOG(sJPEGLog
, LogLevel::Debug
,
222 ("[this=%p] nsJPEGDecoder::Write -- processing JPEG data\n", this));
226 LOG_SCOPE((mozilla::LogModule
*)sJPEGLog
,
227 "nsJPEGDecoder::Write -- entering JPEG_HEADER"
230 // Step 3: read file parameters with jpeg_read_header()
231 if (jpeg_read_header(&mInfo
, TRUE
) == JPEG_SUSPENDED
) {
232 MOZ_LOG(sJPEGDecoderAccountingLog
, LogLevel::Debug
,
233 ("} (JPEG_SUSPENDED)"));
234 return Transition::ContinueUnbuffered(
235 State::JPEG_DATA
); // I/O suspension
238 // Post our size to the superclass
239 PostSize(mInfo
.image_width
, mInfo
.image_height
,
240 ReadOrientationFromEXIF());
242 // Setting the size led to an error.
244 return Transition::TerminateFailure();
247 // If we're doing a metadata decode, we're done.
248 if (IsMetadataDecode()) {
249 return Transition::TerminateSuccess();
252 // We're doing a full decode.
253 switch (mInfo
.jpeg_color_space
) {
257 // By default, we will output directly to BGRA. If we need to apply
258 // special color transforms, this may change.
259 switch (SurfaceFormat::OS_RGBX
) {
260 case SurfaceFormat::B8G8R8X8
:
261 mInfo
.out_color_space
= JCS_EXT_BGRX
;
263 case SurfaceFormat::X8R8G8B8
:
264 mInfo
.out_color_space
= JCS_EXT_XRGB
;
266 case SurfaceFormat::R8G8B8X8
:
267 mInfo
.out_color_space
= JCS_EXT_RGBX
;
271 return Transition::TerminateFailure();
276 // libjpeg can convert from YCCK to CMYK, but not to XRGB.
277 mInfo
.out_color_space
= JCS_CMYK
;
281 MOZ_LOG(sJPEGDecoderAccountingLog
, LogLevel::Debug
,
282 ("} (unknown colorspace (3))"));
283 return Transition::TerminateFailure();
286 if (mCMSMode
!= eCMSMode_Off
) {
287 if ((mInProfile
= GetICCProfile(mInfo
)) != nullptr &&
288 GetCMSOutputProfile()) {
289 uint32_t profileSpace
= qcms_profile_get_color_space(mInProfile
);
291 qcms_data_type outputType
= gfxPlatform::GetCMSOSRGBAType();
292 Maybe
<qcms_data_type
> inputType
;
293 if (profileSpace
== icSigRgbData
) {
294 // We can always color manage RGB profiles since it happens at the
295 // end of the pipeline.
296 inputType
.emplace(outputType
);
297 } else if (profileSpace
== icSigGrayData
&&
298 mInfo
.jpeg_color_space
== JCS_GRAYSCALE
) {
299 // We can only color manage gray profiles if the original color
300 // space is grayscale. This means we must downscale after color
301 // management since the downscaler assumes BGRA.
302 mInfo
.out_color_space
= JCS_GRAYSCALE
;
303 inputType
.emplace(QCMS_DATA_GRAY_8
);
307 // We don't currently support CMYK profiles. The following
308 // code dealt with lcms types. Add something like this
309 // back when we gain support for CMYK.
311 // Adobe Photoshop writes YCCK/CMYK files with inverted data
312 if (mInfo
.out_color_space
== JCS_CMYK
) {
313 type
|= FLAVOR_SH(mInfo
.saw_Adobe_marker
? 1 : 0);
318 // Calculate rendering intent.
319 int intent
= gfxPlatform::GetRenderingIntent();
321 intent
= qcms_profile_get_rendering_intent(mInProfile
);
324 // Create the color management transform.
325 mTransform
= qcms_transform_create(mInProfile
, *inputType
,
326 GetCMSOutputProfile(),
327 outputType
, (qcms_intent
)intent
);
329 } else if (mCMSMode
== eCMSMode_All
) {
330 mTransform
= GetCMSsRGBTransform(SurfaceFormat::OS_RGBX
);
334 // We don't want to use the pipe buffers directly because we don't want
335 // any reads on non-BGRA formatted data.
336 if (mInfo
.out_color_space
== JCS_GRAYSCALE
||
337 mInfo
.out_color_space
== JCS_CMYK
) {
338 mCMSLine
= new (std::nothrow
) uint32_t[mInfo
.image_width
];
341 MOZ_LOG(sJPEGDecoderAccountingLog
, LogLevel::Debug
,
342 ("} (could allocate buffer for color conversion)"));
343 return Transition::TerminateFailure();
347 // Don't allocate a giant and superfluous memory buffer
348 // when not doing a progressive decode.
349 mInfo
.buffered_image
=
350 mDecodeStyle
== PROGRESSIVE
&& jpeg_has_multiple_scans(&mInfo
);
352 /* Used to set up image size so arrays can be allocated */
353 jpeg_calc_output_dimensions(&mInfo
);
355 // We handle the transform outside the pipeline if we are outputting in
356 // grayscale, because the pipeline wants BGRA pixels, particularly the
357 // downscaling filter, so we can't handle it after downscaling as would
359 qcms_transform
* pipeTransform
=
360 mInfo
.out_color_space
!= JCS_GRAYSCALE
? mTransform
: nullptr;
362 Maybe
<SurfacePipe
> pipe
= SurfacePipeFactory::CreateSurfacePipe(
363 this, Size(), OutputSize(), FullFrame(), SurfaceFormat::OS_RGBX
,
364 SurfaceFormat::OS_RGBX
, Nothing(), pipeTransform
, SurfacePipeFlags());
367 MOZ_LOG(sJPEGDecoderAccountingLog
, LogLevel::Debug
,
368 ("} (could not initialize surface pipe)"));
369 return Transition::TerminateFailure();
372 mPipe
= std::move(*pipe
);
374 MOZ_LOG(sJPEGDecoderAccountingLog
, LogLevel::Debug
,
375 (" JPEGDecoderAccounting: nsJPEGDecoder::"
376 "Write -- created image frame with %ux%u pixels",
377 mInfo
.image_width
, mInfo
.image_height
));
379 mState
= JPEG_START_DECOMPRESS
;
380 [[fallthrough
]]; // to start decompressing.
383 case JPEG_START_DECOMPRESS
: {
384 LOG_SCOPE((mozilla::LogModule
*)sJPEGLog
,
385 "nsJPEGDecoder::Write -- entering"
386 " JPEG_START_DECOMPRESS case");
387 // Step 4: set parameters for decompression
389 // FIXME -- Should reset dct_method and dither mode
390 // for final pass of progressive JPEG
392 mInfo
.dct_method
= JDCT_ISLOW
;
393 mInfo
.dither_mode
= JDITHER_FS
;
394 mInfo
.do_fancy_upsampling
= TRUE
;
395 mInfo
.enable_2pass_quant
= FALSE
;
396 mInfo
.do_block_smoothing
= TRUE
;
398 // Step 5: Start decompressor
399 if (jpeg_start_decompress(&mInfo
) == FALSE
) {
400 MOZ_LOG(sJPEGDecoderAccountingLog
, LogLevel::Debug
,
401 ("} (I/O suspension after jpeg_start_decompress())"));
402 return Transition::ContinueUnbuffered(
403 State::JPEG_DATA
); // I/O suspension
406 // If this is a progressive JPEG ...
407 mState
= mInfo
.buffered_image
? JPEG_DECOMPRESS_PROGRESSIVE
408 : JPEG_DECOMPRESS_SEQUENTIAL
;
409 [[fallthrough
]]; // to decompress sequential JPEG.
412 case JPEG_DECOMPRESS_SEQUENTIAL
: {
413 if (mState
== JPEG_DECOMPRESS_SEQUENTIAL
) {
414 LOG_SCOPE((mozilla::LogModule
*)sJPEGLog
,
415 "nsJPEGDecoder::Write -- "
416 "JPEG_DECOMPRESS_SEQUENTIAL case");
418 switch (OutputScanlines()) {
419 case WriteState::NEED_MORE_DATA
:
421 sJPEGDecoderAccountingLog
, LogLevel::Debug
,
422 ("} (I/O suspension after OutputScanlines() - SEQUENTIAL)"));
423 return Transition::ContinueUnbuffered(
424 State::JPEG_DATA
); // I/O suspension
425 case WriteState::FINISHED
:
426 NS_ASSERTION(mInfo
.output_scanline
== mInfo
.output_height
,
427 "We didn't process all of the data!");
430 case WriteState::FAILURE
:
432 MOZ_LOG(sJPEGDecoderAccountingLog
, LogLevel::Debug
,
433 ("} (Error in pipeline from OutputScalines())"));
434 return Transition::TerminateFailure();
437 [[fallthrough
]]; // to decompress progressive JPEG.
440 case JPEG_DECOMPRESS_PROGRESSIVE
: {
441 if (mState
== JPEG_DECOMPRESS_PROGRESSIVE
) {
442 LOG_SCOPE((mozilla::LogModule
*)sJPEGLog
,
443 "nsJPEGDecoder::Write -- JPEG_DECOMPRESS_PROGRESSIVE case");
444 auto AllComponentsSeen
= [](jpeg_decompress_struct
& mInfo
) {
445 bool all_components_seen
= true;
446 if (mInfo
.coef_bits
) {
447 for (int c
= 0; c
< mInfo
.num_components
; ++c
) {
448 bool current_component_seen
= mInfo
.coef_bits
[c
][0] != -1;
449 all_components_seen
&= current_component_seen
;
452 return all_components_seen
;
455 int scan_to_display_first
= 0;
456 bool all_components_seen
;
457 all_components_seen
= AllComponentsSeen(mInfo
);
458 if (all_components_seen
) {
459 scan_to_display_first
= mInfo
.input_scan_number
;
463 status
= jpeg_consume_input(&mInfo
);
465 if (status
== JPEG_REACHED_SOS
|| status
== JPEG_REACHED_EOI
||
466 status
== JPEG_SUSPENDED
) {
467 // record the first scan where all components are present
468 all_components_seen
= AllComponentsSeen(mInfo
);
469 if (!scan_to_display_first
&& all_components_seen
) {
470 scan_to_display_first
= mInfo
.input_scan_number
;
473 } while ((status
!= JPEG_SUSPENDED
) && (status
!= JPEG_REACHED_EOI
));
475 if (!all_components_seen
) {
476 return Transition::ContinueUnbuffered(
477 State::JPEG_DATA
); // I/O suspension
479 // make sure we never try to access the non-exsitent scan 0
480 if (!scan_to_display_first
) {
481 scan_to_display_first
= 1;
483 while (mState
!= JPEG_DONE
) {
484 if (mInfo
.output_scanline
== 0) {
485 int scan
= mInfo
.input_scan_number
;
487 // if we haven't displayed anything yet (output_scan_number==0)
488 // and we have enough data for a complete scan, force output
489 // of the last full scan, but only if this last scan has seen
490 // DC data from all components
491 if ((mInfo
.output_scan_number
== 0) &&
492 (scan
> scan_to_display_first
) &&
493 (status
!= JPEG_REACHED_EOI
)) {
496 MOZ_ASSERT(scan
> 0, "scan number to small!");
497 if (!jpeg_start_output(&mInfo
, scan
)) {
498 MOZ_LOG(sJPEGDecoderAccountingLog
, LogLevel::Debug
,
499 ("} (I/O suspension after jpeg_start_output() -"
501 return Transition::ContinueUnbuffered(
502 State::JPEG_DATA
); // I/O suspension
506 if (mInfo
.output_scanline
== 0xffffff) {
507 mInfo
.output_scanline
= 0;
510 switch (OutputScanlines()) {
511 case WriteState::NEED_MORE_DATA
:
512 if (mInfo
.output_scanline
== 0) {
513 // didn't manage to read any lines - flag so we don't call
514 // jpeg_start_output() multiple times for the same scan
515 mInfo
.output_scanline
= 0xffffff;
517 MOZ_LOG(sJPEGDecoderAccountingLog
, LogLevel::Debug
,
518 ("} (I/O suspension after OutputScanlines() - "
520 return Transition::ContinueUnbuffered(
521 State::JPEG_DATA
); // I/O suspension
522 case WriteState::FINISHED
:
523 NS_ASSERTION(mInfo
.output_scanline
== mInfo
.output_height
,
524 "We didn't process all of the data!");
526 if (!jpeg_finish_output(&mInfo
)) {
527 MOZ_LOG(sJPEGDecoderAccountingLog
, LogLevel::Debug
,
528 ("} (I/O suspension after jpeg_finish_output() -"
530 return Transition::ContinueUnbuffered(
531 State::JPEG_DATA
); // I/O suspension
534 if (jpeg_input_complete(&mInfo
) &&
535 (mInfo
.input_scan_number
== mInfo
.output_scan_number
)) {
538 mInfo
.output_scanline
= 0;
539 mPipe
.ResetToFirstRow();
542 case WriteState::FAILURE
:
544 MOZ_LOG(sJPEGDecoderAccountingLog
, LogLevel::Debug
,
545 ("} (Error in pipeline from OutputScalines())"));
546 return Transition::TerminateFailure();
550 [[fallthrough
]]; // to finish decompressing.
554 LOG_SCOPE((mozilla::LogModule
*)sJPEGLog
,
555 "nsJPEGDecoder::ProcessData -- entering"
558 // Step 7: Finish decompression
560 if (jpeg_finish_decompress(&mInfo
) == FALSE
) {
561 MOZ_LOG(sJPEGDecoderAccountingLog
, LogLevel::Debug
,
562 ("} (I/O suspension after jpeg_finish_decompress() - DONE)"));
563 return Transition::ContinueUnbuffered(
564 State::JPEG_DATA
); // I/O suspension
567 // Make sure we don't feed any more data to libjpeg-turbo.
568 mState
= JPEG_SINK_NON_JPEG_TRAILER
;
571 return Transition::TerminateSuccess();
573 case JPEG_SINK_NON_JPEG_TRAILER
:
574 MOZ_LOG(sJPEGLog
, LogLevel::Debug
,
575 ("[this=%p] nsJPEGDecoder::ProcessData -- entering"
576 " JPEG_SINK_NON_JPEG_TRAILER case\n",
579 MOZ_ASSERT_UNREACHABLE(
580 "Should stop getting data after entering state "
581 "JPEG_SINK_NON_JPEG_TRAILER");
583 return Transition::TerminateSuccess();
586 MOZ_ASSERT_UNREACHABLE(
587 "Should stop getting data after entering state "
590 return Transition::TerminateFailure();
593 MOZ_ASSERT_UNREACHABLE("Escaped the JPEG decoder state machine");
594 return Transition::TerminateFailure();
597 LexerTransition
<nsJPEGDecoder::State
> nsJPEGDecoder::FinishedJPEGData() {
598 // Since we set up an unbuffered read for SIZE_MAX bytes, if we actually read
599 // all that data something is really wrong.
600 MOZ_ASSERT_UNREACHABLE("Read the entire address space?");
601 return Transition::TerminateFailure();
604 Orientation
nsJPEGDecoder::ReadOrientationFromEXIF() {
605 jpeg_saved_marker_ptr marker
;
607 // Locate the APP1 marker, where EXIF data is stored, in the marker list.
608 for (marker
= mInfo
.marker_list
; marker
!= nullptr; marker
= marker
->next
) {
609 if (marker
->marker
== JPEG_APP0
+ 1) {
614 // If we're at the end of the list, there's no EXIF data.
616 return Orientation();
619 // Extract the orientation information.
620 EXIFData exif
= EXIFParser::Parse(marker
->data
,
621 static_cast<uint32_t>(marker
->data_length
));
622 return exif
.orientation
;
625 void nsJPEGDecoder::NotifyDone() {
626 PostFrameStop(Opacity::FULLY_OPAQUE
);
630 WriteState
nsJPEGDecoder::OutputScanlines() {
631 auto result
= mPipe
.WritePixelBlocks
<uint32_t>(
632 [&](uint32_t* aPixelBlock
, int32_t aBlockSize
) {
633 JSAMPROW sampleRow
= (JSAMPROW
)(mCMSLine
? mCMSLine
: aPixelBlock
);
634 if (jpeg_read_scanlines(&mInfo
, &sampleRow
, 1) != 1) {
635 return MakeTuple(/* aWritten */ 0, Some(WriteState::NEED_MORE_DATA
));
638 switch (mInfo
.out_color_space
) {
640 // Already outputted directly to aPixelBlock as BGRA.
641 MOZ_ASSERT(!mCMSLine
);
644 // The transform here does both color management, and converts the
645 // pixels from grayscale to BGRA. This is why we do it here, instead
646 // of using ColorManagementFilter in the SurfacePipe, because the
647 // other filters (e.g. DownscalingFilter) require BGRA pixels.
648 MOZ_ASSERT(mCMSLine
);
649 qcms_transform_data(mTransform
, mCMSLine
, aPixelBlock
,
653 // Convert from CMYK to BGRA
654 MOZ_ASSERT(mCMSLine
);
655 cmyk_convert_bgra(mCMSLine
, aPixelBlock
, aBlockSize
);
659 return MakeTuple(aBlockSize
, Maybe
<WriteState
>());
662 Maybe
<SurfaceInvalidRect
> invalidRect
= mPipe
.TakeInvalidRect();
664 PostInvalidation(invalidRect
->mInputSpaceRect
,
665 Some(invalidRect
->mOutputSpaceRect
));
671 // Override the standard error method in the IJG JPEG decoder code.
673 my_error_exit(j_common_ptr cinfo
) {
674 decoder_error_mgr
* err
= (decoder_error_mgr
*)cinfo
->err
;
676 // Convert error to a browser error code
677 nsresult error_code
= err
->pub
.msg_code
== JERR_OUT_OF_MEMORY
678 ? NS_ERROR_OUT_OF_MEMORY
682 char buffer
[JMSG_LENGTH_MAX
];
684 // Create the message
685 (*err
->pub
.format_message
)(cinfo
, buffer
);
687 fprintf(stderr
, "JPEG decoding error:\n%s\n", buffer
);
690 // Return control to the setjmp point. We pass an nsresult masquerading as
691 // an int, which works because the setjmp() caller casts it back.
692 longjmp(err
->setjmp_buffer
, static_cast<int>(error_code
));
695 /*******************************************************************************
696 * This is the callback routine from the IJG JPEG library used to supply new
697 * data to the decompressor when its input buffer is exhausted. It juggles
698 * multiple buffers in an attempt to avoid unnecessary copying of input data.
700 * (A simpler scheme is possible: It's much easier to use only a single
701 * buffer; when fill_input_buffer() is called, move any unconsumed data
702 * (beyond the current pointer/count) down to the beginning of this buffer and
703 * then load new data into the remaining buffer space. This approach requires
704 * a little more data copying but is far easier to get right.)
706 * At any one time, the JPEG decompressor is either reading from the necko
707 * input buffer, which is volatile across top-level calls to the IJG library,
708 * or the "backtrack" buffer. The backtrack buffer contains the remaining
709 * unconsumed data from the necko buffer after parsing was suspended due
710 * to insufficient data in some previous call to the IJG library.
712 * When suspending, the decompressor will back up to a convenient restart
713 * point (typically the start of the current MCU). The variables
714 * next_input_byte & bytes_in_buffer indicate where the restart point will be
715 * if the current call returns FALSE. Data beyond this point must be
716 * rescanned after resumption, so it must be preserved in case the decompressor
717 * decides to backtrack.
720 * TRUE if additional data is available, FALSE if no data present and
721 * the JPEG library should therefore suspend processing of input stream
722 ******************************************************************************/
724 /******************************************************************************/
725 /* data source manager method */
726 /******************************************************************************/
728 /******************************************************************************/
729 /* data source manager method
730 Initialize source. This is called by jpeg_read_header() before any
731 data is actually read. May leave
732 bytes_in_buffer set to 0 (in which case a fill_input_buffer() call
733 will occur immediately).
736 init_source(j_decompress_ptr jd
) {}
738 /******************************************************************************/
739 /* data source manager method
740 Skip num_bytes worth of data. The buffer pointer and count should
741 be advanced over num_bytes input bytes, refilling the buffer as
742 needed. This is used to skip over a potentially large amount of
743 uninteresting data (such as an APPn marker). In some applications
744 it may be possible to optimize away the reading of the skipped data,
745 but it's not clear that being smart is worth much trouble; large
746 skips are uncommon. bytes_in_buffer may be zero on return.
747 A zero or negative skip count should be treated as a no-op.
750 skip_input_data(j_decompress_ptr jd
, long num_bytes
) {
751 struct jpeg_source_mgr
* src
= jd
->src
;
752 nsJPEGDecoder
* decoder
= (nsJPEGDecoder
*)(jd
->client_data
);
754 if (num_bytes
> (long)src
->bytes_in_buffer
) {
755 // Can't skip it all right now until we get more data from
756 // network stream. Set things up so that fill_input_buffer
757 // will skip remaining amount.
758 decoder
->mBytesToSkip
= (size_t)num_bytes
- src
->bytes_in_buffer
;
759 src
->next_input_byte
+= src
->bytes_in_buffer
;
760 src
->bytes_in_buffer
= 0;
763 // Simple case. Just advance buffer pointer
765 src
->bytes_in_buffer
-= (size_t)num_bytes
;
766 src
->next_input_byte
+= num_bytes
;
770 /******************************************************************************/
771 /* data source manager method
772 This is called whenever bytes_in_buffer has reached zero and more
773 data is wanted. In typical applications, it should read fresh data
774 into the buffer (ignoring the current state of next_input_byte and
775 bytes_in_buffer), reset the pointer & count to the start of the
776 buffer, and return TRUE indicating that the buffer has been reloaded.
777 It is not necessary to fill the buffer entirely, only to obtain at
778 least one more byte. bytes_in_buffer MUST be set to a positive value
779 if TRUE is returned. A FALSE return should only be used when I/O
780 suspension is desired.
783 fill_input_buffer(j_decompress_ptr jd
) {
784 struct jpeg_source_mgr
* src
= jd
->src
;
785 nsJPEGDecoder
* decoder
= (nsJPEGDecoder
*)(jd
->client_data
);
787 if (decoder
->mReading
) {
788 const JOCTET
* new_buffer
= decoder
->mSegment
;
789 uint32_t new_buflen
= decoder
->mSegmentLen
;
791 if (!new_buffer
|| new_buflen
== 0) {
792 return false; // suspend
795 decoder
->mSegmentLen
= 0;
797 if (decoder
->mBytesToSkip
) {
798 if (decoder
->mBytesToSkip
< new_buflen
) {
799 // All done skipping bytes; Return what's left.
800 new_buffer
+= decoder
->mBytesToSkip
;
801 new_buflen
-= decoder
->mBytesToSkip
;
802 decoder
->mBytesToSkip
= 0;
804 // Still need to skip some more data in the future
805 decoder
->mBytesToSkip
-= (size_t)new_buflen
;
806 return false; // suspend
810 decoder
->mBackBufferUnreadLen
= src
->bytes_in_buffer
;
812 src
->next_input_byte
= new_buffer
;
813 src
->bytes_in_buffer
= (size_t)new_buflen
;
814 decoder
->mReading
= false;
819 if (src
->next_input_byte
!= decoder
->mSegment
) {
820 // Backtrack data has been permanently consumed.
821 decoder
->mBackBufferUnreadLen
= 0;
822 decoder
->mBackBufferLen
= 0;
825 // Save remainder of netlib buffer in backtrack buffer
826 const uint32_t new_backtrack_buflen
=
827 src
->bytes_in_buffer
+ decoder
->mBackBufferLen
;
829 // Make sure backtrack buffer is big enough to hold new data.
830 if (decoder
->mBackBufferSize
< new_backtrack_buflen
) {
831 // Check for malformed MARKER segment lengths, before allocating space
833 if (new_backtrack_buflen
> MAX_JPEG_MARKER_LENGTH
) {
834 my_error_exit((j_common_ptr
)(&decoder
->mInfo
));
837 // Round up to multiple of 256 bytes.
838 const size_t roundup_buflen
= ((new_backtrack_buflen
+ 255) >> 8) << 8;
839 JOCTET
* buf
= (JOCTET
*)realloc(decoder
->mBackBuffer
, roundup_buflen
);
842 decoder
->mInfo
.err
->msg_code
= JERR_OUT_OF_MEMORY
;
843 my_error_exit((j_common_ptr
)(&decoder
->mInfo
));
845 decoder
->mBackBuffer
= buf
;
846 decoder
->mBackBufferSize
= roundup_buflen
;
849 // Ensure we actually have a backtrack buffer. Without it, then we know that
850 // there is no data to copy and bytes_in_buffer is already zero.
851 if (decoder
->mBackBuffer
) {
852 // Copy remainder of netlib segment into backtrack buffer.
853 memmove(decoder
->mBackBuffer
+ decoder
->mBackBufferLen
,
854 src
->next_input_byte
, src
->bytes_in_buffer
);
856 MOZ_ASSERT(src
->bytes_in_buffer
== 0);
857 MOZ_ASSERT(decoder
->mBackBufferLen
== 0);
858 MOZ_ASSERT(decoder
->mBackBufferUnreadLen
== 0);
861 // Point to start of data to be rescanned.
862 src
->next_input_byte
= decoder
->mBackBuffer
+ decoder
->mBackBufferLen
-
863 decoder
->mBackBufferUnreadLen
;
864 src
->bytes_in_buffer
+= decoder
->mBackBufferUnreadLen
;
865 decoder
->mBackBufferLen
= (size_t)new_backtrack_buflen
;
866 decoder
->mReading
= true;
871 /******************************************************************************/
872 /* data source manager method */
874 * Terminate source --- called by jpeg_finish_decompress() after all
875 * data has been read to clean up JPEG source manager. NOT called by
876 * jpeg_abort() or jpeg_destroy().
879 term_source(j_decompress_ptr jd
) {
880 nsJPEGDecoder
* decoder
= (nsJPEGDecoder
*)(jd
->client_data
);
882 // This function shouldn't be called if we ran into an error we didn't
884 MOZ_ASSERT(decoder
->mState
!= JPEG_ERROR
,
885 "Calling term_source on a JPEG with mState == JPEG_ERROR!");
887 // Notify using a helper method to get around protectedness issues.
888 decoder
->NotifyDone();
892 } // namespace mozilla
894 ///*************** Inverted CMYK -> RGB conversion *************************
895 /// Input is (Inverted) CMYK stored as 4 bytes per pixel.
896 /// Output is RGB stored as 3 bytes per pixel.
897 /// @param aInput Points to row buffer containing the CMYK bytes for each pixel
899 /// @param aOutput Points to row buffer to write BGRA to.
900 /// @param aWidth Number of pixels in the row.
901 static void cmyk_convert_bgra(uint32_t* aInput
, uint32_t* aOutput
,
903 uint8_t* input
= reinterpret_cast<uint8_t*>(aInput
);
905 for (int32_t i
= 0; i
< aWidth
; ++i
) {
906 // Source is 'Inverted CMYK', output is RGB.
907 // See: http://www.easyrgb.com/math.php?MATH=M12#text12
908 // Or: http://www.ilkeratalay.com/colorspacesfaq.php#rgb
911 // C = ( C * ( 1 - K ) + K )
912 // M = ( M * ( 1 - K ) + K )
913 // Y = ( Y * ( 1 - K ) + K )
915 // From Inverted CMYK to CMY is thus:
916 // C = ( (1-iC) * (1 - (1-iK)) + (1-iK) ) => 1 - iC*iK
919 // Convert from CMY (0..1) to RGB (0..1)
920 // R = 1 - C => 1 - (1 - iC*iK) => iC*iK
921 // G = 1 - M => 1 - (1 - iM*iK) => iM*iK
922 // B = 1 - Y => 1 - (1 - iY*iK) => iY*iK
924 // Convert from Inverted CMYK (0..255) to RGB (0..255)
925 const uint32_t iC
= input
[0];
926 const uint32_t iM
= input
[1];
927 const uint32_t iY
= input
[2];
928 const uint32_t iK
= input
[3];
930 const uint8_t r
= iC
* iK
/ 255;
931 const uint8_t g
= iM
* iK
/ 255;
932 const uint8_t b
= iY
* iK
/ 255;
934 *aOutput
++ = (0xFF << mozilla::gfx::SurfaceFormatBit::OS_A
) |
935 (r
<< mozilla::gfx::SurfaceFormatBit::OS_R
) |
936 (g
<< mozilla::gfx::SurfaceFormatBit::OS_G
) |
937 (b
<< mozilla::gfx::SurfaceFormatBit::OS_B
);