nsIconDecoder.cpp (4409B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ 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 "nsIconDecoder.h" 8 #include "RasterImage.h" 9 #include "SurfacePipeFactory.h" 10 #include "gfxPlatform.h" 11 12 using namespace mozilla::gfx; 13 14 namespace mozilla { 15 namespace image { 16 17 static const uint32_t ICON_HEADER_SIZE = 4; 18 19 nsIconDecoder::nsIconDecoder(RasterImage* aImage) 20 : Decoder(aImage), 21 mLexer(Transition::To(State::HEADER, ICON_HEADER_SIZE), 22 Transition::TerminateSuccess()), 23 mBytesPerRow() // set by ReadHeader() 24 { 25 // Nothing to do 26 } 27 28 nsIconDecoder::~nsIconDecoder() {} 29 30 LexerResult nsIconDecoder::DoDecode(SourceBufferIterator& aIterator, 31 IResumable* aOnResume) { 32 MOZ_ASSERT(!HasError(), "Shouldn't call DoDecode after error!"); 33 34 return mLexer.Lex(aIterator, aOnResume, 35 [=](State aState, const char* aData, size_t aLength) { 36 switch (aState) { 37 case State::HEADER: 38 return ReadHeader(aData); 39 case State::ROW_OF_PIXELS: 40 return ReadRowOfPixels(aData, aLength); 41 case State::FINISH: 42 return Finish(); 43 default: 44 MOZ_CRASH("Unknown State"); 45 } 46 }); 47 } 48 49 LexerTransition<nsIconDecoder::State> nsIconDecoder::ReadHeader( 50 const char* aData) { 51 // Grab the width and height. 52 uint8_t width = uint8_t(aData[0]); 53 uint8_t height = uint8_t(aData[1]); 54 SurfaceFormat format = SurfaceFormat(aData[2]); 55 bool transform = bool(aData[3]); 56 57 if (format != SurfaceFormat::B8G8R8A8 && format != SurfaceFormat::B8G8R8X8 && 58 format != SurfaceFormat::R8G8B8A8 && format != SurfaceFormat::R8G8B8X8 && 59 format != SurfaceFormat::A8R8G8B8 && format != SurfaceFormat::X8R8G8B8) { 60 return Transition::TerminateFailure(); 61 } 62 63 // FIXME(aosmond): On OSX we get the icon in device space and already 64 // premultiplied, so we can't support the surface flags with icons right now. 65 SurfacePipeFlags pipeFlags = SurfacePipeFlags(); 66 if (transform) { 67 if (mCMSMode == CMSMode::All) { 68 mTransform = GetCMSsRGBTransform(format); 69 } 70 71 if (!(GetSurfaceFlags() & SurfaceFlags::NO_PREMULTIPLY_ALPHA)) { 72 pipeFlags |= SurfacePipeFlags::PREMULTIPLY_ALPHA; 73 } 74 } 75 76 // The input is 32bpp, so we expect 4 bytes of data per pixel. 77 mBytesPerRow = width * 4; 78 79 // Post our size to the superclass. 80 PostSize(width, height); 81 82 if (WantsFrameCount()) { 83 PostFrameCount(/* aFrameCount */ 1); 84 } 85 86 // Icons have alpha. 87 PostHasTransparency(); 88 89 // If we're doing a metadata decode, we're done. 90 if (IsMetadataDecode()) { 91 return Transition::TerminateSuccess(); 92 } 93 94 MOZ_ASSERT(!mImageData, "Already have a buffer allocated?"); 95 Maybe<SurfacePipe> pipe = SurfacePipeFactory::CreateSurfacePipe( 96 this, Size(), OutputSize(), FullFrame(), format, SurfaceFormat::OS_RGBA, 97 /* aAnimParams */ Nothing(), mTransform, pipeFlags); 98 if (!pipe) { 99 return Transition::TerminateFailure(); 100 } 101 102 mPipe = std::move(*pipe); 103 104 MOZ_ASSERT(mImageData, "Should have a buffer now"); 105 106 return Transition::To(State::ROW_OF_PIXELS, mBytesPerRow); 107 } 108 109 LexerTransition<nsIconDecoder::State> nsIconDecoder::ReadRowOfPixels( 110 const char* aData, size_t aLength) { 111 MOZ_ASSERT(aLength % 4 == 0, "Rows should contain a multiple of four bytes"); 112 113 auto result = mPipe.WriteBuffer(reinterpret_cast<const uint32_t*>(aData)); 114 MOZ_ASSERT(result != WriteState::FAILURE); 115 116 Maybe<SurfaceInvalidRect> invalidRect = mPipe.TakeInvalidRect(); 117 if (invalidRect) { 118 PostInvalidation(invalidRect->mInputSpaceRect, 119 Some(invalidRect->mOutputSpaceRect)); 120 } 121 122 return result == WriteState::FINISHED 123 ? Transition::To(State::FINISH, 0) 124 : Transition::To(State::ROW_OF_PIXELS, mBytesPerRow); 125 } 126 127 LexerTransition<nsIconDecoder::State> nsIconDecoder::Finish() { 128 PostFrameStop(); 129 PostDecodeDone(); 130 131 return Transition::TerminateSuccess(); 132 } 133 134 } // namespace image 135 } // namespace mozilla